# HG changeset patch
# User Paul McGuire <ptmcg@austin.rr.com>
# Date 1349135442 0
#      Mon Oct 01 23:50:42 2012 +0000
# Node ID ee11877283be72c01e9132c20abf73b3891f98d2
# Parent  9e68e57f81f41e2a63c9ac76ff543ae008265345
Make tag for release 1.5.2

diff --git a/CHANGES b/CHANGES
new file mode 100644
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,1440 @@
+==========
+Change Log
+==========
+
+Version 1.5.2 - April, 2009
+------------------------------
+- Added pyparsing_py3.py module, so that Python 3 users can use
+  pyparsing by changing their pyparsing import statement to:
+  
+      import pyparsing_py3
+
+  Thanks for help from Patrick Laban and his friend Geremy 
+  Condra on the pyparsing wiki.
+  
+- Removed __slots__ declaration on ParseBaseException, for
+  compatibility with IronPython 2.0.1.  Raised by David
+  Lawler on the pyparsing wiki, thanks David!
+  
+- Fixed bug in SkipTo/failOn handling - caught by eagle eye 
+  cpennington on the pyparsing wiki!
+
+- Fixed second bug in SkipTo when using the ignore constructor
+  argument, reported by Catherine Devlin, thanks!
+  
+- Fixed obscure bug reported by Eike Welk when using a class
+  as a ParseAction with an errant __getitem__ method.
+
+- Simplified exception stack traces when reporting parse 
+  exceptions back to caller of parseString or parseFile - thanks
+  to a tip from Peter Otten on comp.lang.python.
+
+- Changed behavior of scanString to avoid infinitely looping on
+  expressions that match zero-length strings.  Prompted by a
+  question posted by ellisonbg on the wiki.
+
+- Enhanced classes that take a list of expressions (And, Or, 
+  MatchFirst, and Each) to accept generator expressions also.
+  This can be useful when generating lists of alternative
+  expressions, as in this case, where the user wanted to match
+  any repetitions of '+', '*', '#', or '.', but not mixtures
+  of them (that is, match '+++', but not '+-+'):
+  
+      codes = "+*#."
+      format = MatchFirst(Word(c) for c in codes)
+      
+  Based on a problem posed by Denis Spir on the Python tutor
+  list.
+
+- Added new example eval_arith.py, which extends the example
+  simpleArith.py to actually evaluate the parsed expressions.
+
+
+Version 1.5.1 - October, 2008
+-------------------------------
+- Added new helper method originalTextFor, to replace the use of
+  the current keepOriginalText parse action.  Now instead of 
+  using the parse action, as in:
+  
+      fullName = Word(alphas) + Word(alphas)
+      fullName.setParseAction(keepOriginalText)
+      
+  (in this example, we used keepOriginalText to restore any white
+  space that may have been skipped between the first and last
+  names)
+  You can now write:
+  
+      fullName = originalTextFor(Word(alphas) + Word(alphas))
+      
+  The implementation of originalTextFor is simpler and faster than
+  keepOriginalText, and does not depend on using the inspect or
+  imp modules.
+  
+- Added optional parseAll argument to parseFile, to be consistent
+  with parseAll argument to parseString.  Posted by pboucher on the
+  pyparsing wiki, thanks!
+
+- Added failOn argument to SkipTo, so that grammars can define
+  literal strings or pyparsing expressions which, if found in the
+  skipped text, will cause SkipTo to fail.  Useful to prevent 
+  SkipTo from reading past terminating expression.  Instigated by
+  question posed by Aki Niimura on the pyparsing wiki.
+
+- Fixed bug in nestedExpr if multi-character expressions are given
+  for nesting delimiters.  Patch provided by new pyparsing user,
+  Hans-Martin Gaudecker - thanks, H-M!
+
+- Removed dependency on xml.sax.saxutils.escape, and included
+  internal implementation instead - proposed by Mike Droettboom on
+  the pyparsing mailing list, thanks Mike!  Also fixed erroneous
+  mapping in replaceHTMLEntity of &quot; to ', now correctly maps
+  to ".  (Also added support for mapping &apos; to '.)
+
+- Fixed typo in ParseResults.insert, found by Alejandro Dubrovsky,
+  good catch!
+
+- Added __dir__() methods to ParseBaseException and ParseResults,
+  to support new dir() behavior in Py2.6 and Py3.0.  If dir() is
+  called on a ParseResults object, the returned list will include
+  the base set of attribute names, plus any results names that are
+  defined.
+
+- Fixed bug in ParseResults.asXML(), in which the first named
+  item within a ParseResults gets reported with an <ITEM> tag 
+  instead of with the correct results name.
+  
+- Fixed bug in '-' error stop, when '-' operator is used inside a 
+  Combine expression.
+
+- Reverted generator expression to use list comprehension, for 
+  better compatibility with old versions of Python.  Reported by
+  jester/artixdesign on the SourceForge pyparsing discussion list.
+
+- Fixed bug in parseString(parseAll=True), when the input string
+  ends with a comment or whitespace.
+
+- Fixed bug in LineStart and LineEnd that did not recognize any
+  special whitespace chars defined using ParserElement.setDefault-
+  WhitespaceChars, found while debugging an issue for Marek Kubica,
+  thanks for the new test case, Marek!
+
+- Made Forward class more tolerant of subclassing.
+
+
+Version 1.5.0 - June, 2008
+--------------------------
+This version of pyparsing includes work on two long-standing
+FAQ's: support for forcing parsing of the complete input string
+(without having to explicitly append StringEnd() to the grammar),
+and a method to improve the mechanism of detecting where syntax
+errors occur in an input string with various optional and
+alternative paths.  This release also includes a helper method
+to simplify definition of indentation-based grammars.  With
+these changes (and the past few minor updates), I thought it was
+finally time to bump the minor rev number on pyparsing - so
+1.5.0 is now available!  Read on...
+
+- AT LAST!!!  You can now call parseString and have it raise
+  an exception if the expression does not parse the entire
+  input string.  This has been an FAQ for a LONG time.
+
+  The parseString method now includes an optional parseAll
+  argument (default=False).  If parseAll is set to True, then
+  the given parse expression must parse the entire input
+  string.  (This is equivalent to adding StringEnd() to the
+  end of the expression.)  The default value is False to
+  retain backward compatibility.
+
+  Inspired by MANY requests over the years, most recently by
+  ecir-hana on the pyparsing wiki!
+
+- Added new operator '-' for composing grammar sequences. '-'
+  behaves just like '+' in creating And expressions, but '-'
+  is used to mark grammar structures that should stop parsing
+  immediately and report a syntax error, rather than just
+  backtracking to the last successful parse and trying another
+  alternative.  For instance, running the following code:
+
+    port_definition = Keyword("port") + '=' + Word(nums)
+    entity_definition = Keyword("entity") + "{" +
+        Optional(port_definition) + "}"
+
+    entity_definition.parseString("entity { port 100 }")
+
+  pyparsing fails to detect the missing '=' in the port definition.
+  But, since this expression is optional, pyparsing then proceeds
+  to try to match the closing '}' of the entity_definition.  Not
+  finding it, pyparsing reports that there was no '}' after the '{'
+  character.  Instead, we would like pyparsing to parse the 'port'
+  keyword, and if not followed by an equals sign and an integer,
+  to signal this as a syntax error.
+
+  This can now be done simply by changing the port_definition to:
+
+    port_definition = Keyword("port") - '=' + Word(nums)
+
+  Now after successfully parsing 'port', pyparsing must also find
+  an equals sign and an integer, or it will raise a fatal syntax
+  exception.
+
+  By judicious insertion of '-' operators, a pyparsing developer
+  can have their grammar report much more informative syntax error
+  messages.
+
+  Patches and suggestions proposed by several contributors on
+  the pyparsing mailing list and wiki - special thanks to
+  Eike Welk and Thomas/Poldy on the pyparsing wiki!
+
+- Added indentedBlock helper method, to encapsulate the parse
+  actions and indentation stack management needed to keep track of
+  indentation levels.  Use indentedBlock to define grammars for
+  indentation-based grouping grammars, like Python's.
+
+  indentedBlock takes up to 3 parameters:
+    - blockStatementExpr - expression defining syntax of statement
+        that is repeated within the indented block
+    - indentStack - list created by caller to manage indentation
+        stack (multiple indentedBlock expressions
+        within a single grammar should share a common indentStack)
+    - indent - boolean indicating whether block must be indented
+        beyond the the current level; set to False for block of
+        left-most statements (default=True)
+
+  A valid block must contain at least one indented statement.
+
+- Fixed bug in nestedExpr in which ignored expressions needed
+  to be set off with whitespace.  Reported by Stefaan Himpe,
+  nice catch!
+
+- Expanded multiplication of an expression by a tuple, to
+  accept tuple values of None:
+  . expr*(n,None) or expr*(n,) is equivalent
+    to expr*n + ZeroOrMore(expr)
+    (read as "at least n instances of expr")
+  . expr*(None,n) is equivalent to expr*(0,n)
+    (read as "0 to n instances of expr")
+  . expr*(None,None) is equivalent to ZeroOrMore(expr)
+  . expr*(1,None) is equivalent to OneOrMore(expr)
+
+  Note that expr*(None,n) does not raise an exception if
+  more than n exprs exist in the input stream; that is,
+  expr*(None,n) does not enforce a maximum number of expr
+  occurrences.  If this behavior is desired, then write
+  expr*(None,n) + ~expr
+
+- Added None as a possible operator for operatorPrecedence.
+  None signifies "no operator", as in multiplying m times x
+  in "y=mx+b".
+
+- Fixed bug in Each, reported by Michael Ramirez, in which the
+  order of terms in the Each affected the parsing of the results.
+  Problem was due to premature grouping of the expressions in
+  the overall Each during grammar construction, before the
+  complete Each was defined.  Thanks, Michael!
+
+- Also fixed bug in Each in which Optional's with default values
+  were not getting the defaults added to the results of the
+  overall Each expression.
+
+- Fixed a bug in Optional in which results names were not
+  assigned if a default value was supplied.
+
+- Cleaned up Py3K compatibility statements, including exception
+  construction statements, and better equivalence between _ustr
+  and basestring, and __nonzero__ and __bool__.
+
+
+Version 1.4.11 - February, 2008
+-------------------------------
+- With help from Robert A. Clark, this version of pyparsing
+  is compatible with Python 3.0a3.  Thanks for the help,
+  Robert!
+
+- Added WordStart and WordEnd positional classes, to support
+  expressions that must occur at the start or end of a word.
+  Proposed by piranha on the pyparsing wiki, good idea!
+
+- Added matchOnlyAtCol helper parser action, to simplify
+  parsing log or data files that have optional fields that are
+  column dependent.  Inspired by a discussion thread with
+  hubritic on comp.lang.python.
+
+- Added withAttribute.ANY_VALUE as a match-all value when using
+  withAttribute.  Used to ensure that an attribute is present,
+  without having to match on the actual attribute value.
+
+- Added get() method to ParseResults, similar to dict.get().
+  Suggested by new pyparsing user, Alejandro Dubrovksy, thanks!
+
+- Added '==' short-cut to see if a given string matches a
+  pyparsing expression.  For instance, you can now write:
+
+    integer = Word(nums)
+    if "123" == integer:
+       # do something
+
+    print [ x for x in "123 234 asld".split() if x==integer ]
+    # prints ['123', '234']
+
+- Simplified the use of nestedExpr when using an expression for
+  the opening or closing delimiters.  Now the content expression
+  will not have to explicitly negate closing delimiters.  Found
+  while working with dfinnie on GHOP Task #277, thanks!
+
+- Fixed bug when defining ignorable expressions that are
+  later enclosed in a wrapper expression (such as ZeroOrMore,
+  OneOrMore, etc.) - found while working with Prabhu
+  Gurumurthy, thanks Prahbu!
+
+- Fixed bug in withAttribute in which keys were automatically
+  converted to lowercase, making it impossible to match XML
+  attributes with uppercase characters in them.  Using with-
+  Attribute requires that you reference attributes in all
+  lowercase if parsing HTML, and in correct case when parsing
+  XML.
+
+- Changed '<<' operator on Forward to return None, since this
+  is really used as a pseudo-assignment operator, not as a
+  left-shift operator.  By returning None, it is easier to
+  catch faulty statements such as a << b | c, where precedence
+  of operations causes the '|' operation to be performed
+  *after* inserting b into a, so no alternation is actually
+  implemented.  The correct form is a << (b | c).  With this
+  change, an error will be reported instead of silently
+  clipping the alternative term.  (Note: this may break some
+  existing code, but if it does, the code had a silent bug in
+  it anyway.)  Proposed by wcbarksdale on the pyparsing wiki,
+  thanks!
+
+- Several unit tests were added to pyparsing's regression
+  suite, courtesy of the Google Highly-Open Participation
+  Contest.  Thanks to all who administered and took part in
+  this event!
+
+
+Version 1.4.10 - December 9, 2007
+---------------------------------
+- Fixed bug introduced in v1.4.8, parse actions were called for
+  intermediate operator levels, not just the deepest matching
+  operation level.  Again, big thanks to Torsten Marek for
+  helping isolate this problem!
+
+
+Version 1.4.9 - December 8, 2007
+--------------------------------
+- Added '*' multiplication operator support when creating
+  grammars, accepting either an integer, or a two-integer
+  tuple multiplier, as in:
+    ipAddress = Word(nums) + ('.'+Word(nums))*3
+    usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
+  If multiplying by a tuple, the two integer values represent
+  min and max multiples.  Suggested by Vincent of eToy.com,
+  great idea, Vincent!
+
+- Fixed bug in nestedExpr, original version was overly greedy!
+  Thanks to Michael Ramirez for raising this issue.
+
+- Fixed internal bug in ParseResults - when an item was deleted,
+  the key indices were not updated.  Thanks to Tim Mitchell for
+  posting a bugfix patch to the SF bug tracking system!
+
+- Fixed internal bug in operatorPrecedence - when the results of
+  a right-associative term were sent to a parse action, the wrong
+  tokens were sent.  Reported by Torsten Marek, nice job!
+
+- Added pop() method to ParseResults.  If pop is called with an
+  integer or with no arguments, it will use list semantics and
+  update the ParseResults' list of tokens.  If pop is called with
+  a non-integer (a string, for instance), then it will use dict
+  semantics and update the ParseResults' internal dict.
+  Suggested by Donn Ingle, thanks Donn!
+
+- Fixed quoted string built-ins to accept '\xHH' hex characters
+  within the string.
+
+
+Version 1.4.8 - October, 2007
+-----------------------------
+- Added new helper method nestedExpr to easily create expressions
+  that parse lists of data in nested parentheses, braces, brackets,
+  etc.
+
+- Added withAttribute parse action helper, to simplify creating
+  filtering parse actions to attach to expressions returned by
+  makeHTMLTags and makeXMLTags.  Use withAttribute to qualify a
+  starting tag with one or more required attribute values, to avoid
+  false matches on common tags such as <TD> or <DIV>.
+
+- Added new examples nested.py and withAttribute.py to demonstrate
+  the new features.
+
+- Added performance speedup to grammars using operatorPrecedence,
+  instigated by Stefan Reich�r - thanks for the feedback, Stefan!
+
+- Fixed bug/typo when deleting an element from a ParseResults by
+  using the element's results name.
+
+- Fixed whitespace-skipping bug in wrapper classes (such as Group,
+  Suppress, Combine, etc.) and when using setDebug(), reported by
+  new pyparsing user dazzawazza on SourceForge, nice job!
+
+- Added restriction to prevent defining Word or CharsNotIn expressions
+  with minimum length of 0 (should use Optional if this is desired),
+  and enhanced docstrings to reflect this limitation.  Issue was
+  raised by Joey Tallieu, who submitted a patch with a slightly
+  different solution.  Thanks for taking the initiative, Joey, and
+  please keep submitting your ideas!
+
+- Fixed bug in makeHTMLTags that did not detect HTML tag attributes
+  with no '= value' portion (such as "<td nowrap>"), reported by
+  hamidh on the pyparsing wiki - thanks!
+
+- Fixed minor bug in makeHTMLTags and makeXMLTags, which did not
+  accept whitespace in closing tags.
+
+
+Version 1.4.7 - July, 2007
+--------------------------
+- NEW NOTATION SHORTCUT: ParserElement now accepts results names using
+  a notational shortcut, following the expression with the results name
+  in parentheses.  So this:
+
+    stats = "AVE:" + realNum.setResultsName("average") + \
+            "MIN:" + realNum.setResultsName("min") + \
+            "MAX:" + realNum.setResultsName("max")
+
+  can now be written as this:
+
+    stats = "AVE:" + realNum("average") + \
+            "MIN:" + realNum("min") + \
+            "MAX:" + realNum("max")
+
+  The intent behind this change is to make it simpler to define results
+  names for significant fields within the expression, while keeping
+  the grammar syntax clean and uncluttered.
+
+- Fixed bug when packrat parsing is enabled, with cached ParseResults
+  being updated by subsequent parsing.  Reported on the pyparsing
+  wiki by Kambiz, thanks!
+
+- Fixed bug in operatorPrecedence for unary operators with left
+  associativity, if multiple operators were given for the same term.
+
+- Fixed bug in example simpleBool.py, corrected precedence of "and" vs.
+  "or" operations.
+
+- Fixed bug in Dict class, in which keys were converted to strings
+  whether they needed to be or not.  Have narrowed this logic to
+  convert keys to strings only if the keys are ints (which would
+  confuse __getitem__ behavior for list indexing vs. key lookup).
+
+- Added ParserElement method setBreak(), which will invoke the pdb
+  module's set_trace() function when this expression is about to be
+  parsed.
+
+- Fixed bug in StringEnd in which reading off the end of the input
+  string raises an exception - should match.  Resolved while
+  answering a question for Shawn on the pyparsing wiki.
+
+
+Version 1.4.6 - April, 2007
+---------------------------
+- Simplified constructor for ParseFatalException, to support common
+  exception construction idiom:
+    raise ParseFatalException, "unexpected text: 'Spanish Inquisition'"
+
+- Added method getTokensEndLoc(), to be called from within a parse action,
+  for those parse actions that need both the starting *and* ending
+  location of the parsed tokens within the input text.
+
+- Enhanced behavior of keepOriginalText so that named parse fields are
+  preserved, even though tokens are replaced with the original input
+  text matched by the current expression.  Also, cleaned up the stack
+  traversal to be more robust.  Suggested by Tim Arnold - thanks, Tim!
+
+- Fixed subtle bug in which countedArray (and similar dynamic
+  expressions configured in parse actions) failed to match within Or,
+  Each, FollowedBy, or NotAny.  Reported by Ralf Vosseler, thanks for
+  your patience, Ralf!
+
+- Fixed Unicode bug in upcaseTokens and downcaseTokens parse actions,
+  scanString, and default debugging actions; reported (and patch submitted)
+  by Nikolai Zamkovoi, spasibo!
+
+- Fixed bug when saving a tuple as a named result.  The returned
+  token list gave the proper tuple value, but accessing the result by
+  name only gave the first element of the tuple.  Reported by
+  Poromenos, nice catch!
+
+- Fixed bug in makeHTMLTags/makeXMLTags, which failed to match tag
+  attributes with namespaces.
+
+- Fixed bug in SkipTo when setting include=True, to have the skipped-to
+  tokens correctly included in the returned data.  Reported by gunars on
+  the pyparsing wiki, thanks!
+
+- Fixed typobug in OnceOnly.reset method, omitted self argument.
+  Submitted by eike welk, thanks for the lint-picking!
+
+- Added performance enhancement to Forward class, suggested by
+  akkartik on the pyparsing Wiki discussion, nice work!
+
+- Added optional asKeyword to Word constructor, to indicate that the
+  given word pattern should be matched only as a keyword, that is, it
+  should only match if it is within word boundaries.
+
+- Added S-expression parser to examples directory.
+
+- Added macro substitution example to examples directory.
+
+- Added holaMundo.py example, excerpted from Marco Alfonso's blog -
+  muchas gracias, Marco!
+
+- Modified internal cyclic references in ParseResults to use weakrefs;
+  this should help reduce the memory footprint of large parsing
+  programs, at some cost to performance (3-5%). Suggested by bca48150 on
+  the pyparsing wiki, thanks!
+
+- Enhanced the documentation describing the vagaries and idiosyncracies
+  of parsing strings with embedded tabs, and the impact on:
+  . parse actions
+  . scanString
+  . col and line helper functions
+  (Suggested by eike welk in response to some unexplained inconsistencies
+  between parsed location and offsets in the input string.)
+
+- Cleaned up internal decorators to preserve function names,
+  docstrings, etc.
+
+
+Version 1.4.5 - December, 2006
+------------------------------
+- Removed debugging print statement from QuotedString class.  Sorry
+  for not stripping this out before the 1.4.4 release!
+
+- A significant performance improvement, the first one in a while!
+  For my Verilog parser, this version of pyparsing is about double the
+  speed - YMMV.
+
+- Added support for pickling of ParseResults objects.  (Reported by
+  Jeff Poole, thanks Jeff!)
+
+- Fixed minor bug in makeHTMLTags that did not recognize tag attributes
+  with embedded '-' or '_' characters.  Also, added support for
+  passing expressions to makeHTMLTags and makeXMLTags, and used this
+  feature to define the globals anyOpenTag and anyCloseTag.
+
+- Fixed error in alphas8bit, I had omitted the y-with-umlaut character.
+
+- Added punc8bit string to complement alphas8bit - it contains all the
+  non-alphabetic, non-blank 8-bit characters.
+
+- Added commonHTMLEntity expression, to match common HTML "ampersand"
+  codes, such as "&lt;", "&gt;", "&amp;", "&nbsp;", and "&quot;".  This
+  expression also defines a results name 'entity', which can be used
+  to extract the entity field (that is, "lt", "gt", etc.).  Also added
+  built-in parse action replaceHTMLEntity, which can be attached to
+  commonHTMLEntity to translate "&lt;", "&gt;", "&amp;", "&nbsp;", and
+  "&quot;" to "<", ">", "&", " ", and "'".
+
+- Added example, htmlStripper.py, that strips HTML tags and scripts
+  from HTML pages.  It also translates common HTML entities to their
+  respective characters.
+
+
+Version 1.4.4 - October, 2006
+-------------------------------
+- Fixed traceParseAction decorator to also trap and record exception
+  returns from parse actions, and to handle parse actions with 0,
+  1, 2, or 3 arguments.
+
+- Enhanced parse action normalization to support using classes as
+  parse actions; that is, the class constructor is called at parse
+  time and the __init__ function is called with 0, 1, 2, or 3
+  arguments.  If passing a class as a parse action, the __init__
+  method must use one  of the valid parse action parameter list
+  formats. (This technique is useful when using pyparsing to compile
+  parsed text into a series of application objects - see the new
+  example simpleBool.py.)
+
+- Fixed bug in ParseResults when setting an item using an integer
+  index. (Reported by Christopher Lambacher, thanks!)
+
+- Fixed whitespace-skipping bug, patch submitted by Paolo Losi -
+  grazie, Paolo!
+
+- Fixed bug when a Combine contained an embedded Forward expression,
+  reported by cie on the pyparsing wiki - good catch!
+
+- Fixed listAllMatches bug, when a listAllMatches result was
+  nested within another result. (Reported by don pasquale on
+  comp.lang.python, well done!)
+
+- Fixed bug in ParseResults items() method, when returning an item
+  marked as listAllMatches=True
+
+- Fixed bug in definition of cppStyleComment (and javaStyleComment)
+  in which '//' line comments were not continued to the next line
+  if the line ends with a '\'.  (Reported by eagle-eyed Ralph
+  Corderoy!)
+
+- Optimized re's for cppStyleComment and quotedString for better
+  re performance - also provided by Ralph Corderoy, thanks!
+
+- Added new example, indentedGrammarExample.py, showing how to
+  define a grammar using indentation to show grouping (as Python
+  does for defining statement nesting).  Instigated by an e-mail
+  discussion with Andrew Dalke, thanks Andrew!
+
+- Added new helper operatorPrecedence (based on e-mail list discussion
+  with Ralph Corderoy and Paolo Losi), to facilitate definition of
+  grammars for expressions with unary and binary operators.  For
+  instance, this grammar defines a 6-function arithmetic expression
+  grammar, with unary plus and minus, proper operator precedence,and
+  right- and left-associativity:
+
+    expr = operatorPrecedence( operand,
+        [("!", 1, opAssoc.LEFT),
+         ("^", 2, opAssoc.RIGHT),
+         (oneOf("+ -"), 1, opAssoc.RIGHT),
+         (oneOf("* /"), 2, opAssoc.LEFT),
+         (oneOf("+ -"), 2, opAssoc.LEFT),]
+        )
+
+  Also added example simpleArith.py and simpleBool.py to provide
+  more detailed code samples using this new helper method.
+
+- Added new helpers matchPreviousLiteral and matchPreviousExpr, for
+  creating adaptive parsing expressions that match the same content
+  as was parsed in a previous parse expression.  For instance:
+
+        first = Word(nums)
+        matchExpr = first + ":" + matchPreviousLiteral(first)
+
+  will match "1:1", but not "1:2".  Since this matches at the literal
+  level, this will also match the leading "1:1" in "1:10".
+
+  In contrast:
+
+        first = Word(nums)
+        matchExpr = first + ":" + matchPreviousExpr(first)
+
+  will *not* match the leading "1:1" in "1:10"; the expressions are
+  evaluated first, and then compared, so "1" is compared with "10".
+
+- Added keepOriginalText parse action.  Sometimes pyparsing's
+  whitespace-skipping leaves out too much whitespace.  Adding this
+  parse action will restore any internal whitespace for a parse
+  expression.  This is especially useful when defining expressions
+  for scanString or transformString applications.
+
+- Added __add__ method for ParseResults class, to better support
+  using Python sum built-in for summing ParseResults objects returned
+  from scanString.
+
+- Added reset method for the new OnlyOnce class wrapper for parse
+  actions (to allow a grammar to be used multiple times).
+
+- Added optional maxMatches argument to scanString and searchString,
+  to short-circuit scanning after 'n' expression matches are found.
+
+
+Version 1.4.3 - July, 2006
+------------------------------
+- Fixed implementation of multiple parse actions for an expression
+  (added in 1.4.2).
+  . setParseAction() reverts to its previous behavior, setting
+    one (or more) actions for an expression, overwriting any
+    action or actions previously defined
+  . new method addParseAction() appends one or more parse actions
+    to the list of parse actions attached to an expression
+  Now it is harder to accidentally append parse actions to an
+  expression, when what you wanted to do was overwrite whatever had
+  been defined before.  (Thanks, Jean-Paul Calderone!)
+
+- Simplified interface to parse actions that do not require all 3
+  parse action arguments.  Very rarely do parse actions require more
+  than just the parsed tokens, yet parse actions still require all
+  3 arguments including the string being parsed and the location
+  within the string where the parse expression was matched.  With this
+  release, parse actions may now be defined to be called as:
+  . fn(string,locn,tokens)  (the current form)
+  . fn(locn,tokens)
+  . fn(tokens)
+  . fn()
+  The setParseAction and addParseAction methods will internally decorate
+  the provided parse actions with compatible wrappers to conform to
+  the full (string,locn,tokens) argument sequence.
+
+- REMOVED SUPPORT FOR RETURNING PARSE LOCATION FROM A PARSE ACTION.
+  I announced this in March, 2004, and gave a final warning in the last
+  release.  Now you can return a tuple from a parse action, and it will
+  be treated like any other return value (i.e., the tuple will be
+  substituted for the incoming tokens passed to the parse action,
+  which is useful when trying to parse strings into tuples).
+
+- Added setFailAction method, taking a callable function fn that
+  takes the arguments fn(s,loc,expr,err) where:
+  . s - string being parsed
+  . loc - location where expression match was attempted and failed
+  . expr - the parse expression that failed
+  . err - the exception thrown
+  The function returns no values.  It may throw ParseFatalException
+  if it is desired to stop parsing immediately.
+  (Suggested by peter21081944 on wikispaces.com)
+
+- Added class OnlyOnce as helper wrapper for parse actions.  OnlyOnce
+  only permits a parse action to be called one time, after which
+  all subsequent calls throw a ParseException.
+
+- Added traceParseAction decorator to help debug parse actions.
+  Simply insert "@traceParseAction" ahead of the definition of your
+  parse action, and each invocation will be displayed, along with
+  incoming arguments, and returned value.
+
+- Fixed bug when copying ParserElements using copy() or
+  setResultsName().  (Reported by Dan Thill, great catch!)
+
+- Fixed bug in asXML() where token text contains <, >, and &
+  characters - generated XML now escapes these as &lt;, &gt; and
+  &amp;.  (Reported by Jacek Sieka, thanks!)
+
+- Fixed bug in SkipTo() when searching for a StringEnd(). (Reported
+  by Pete McEvoy, thanks Pete!)
+
+- Fixed "except Exception" statements, the most critical added as part
+  of the packrat parsing enhancement.  (Thanks, Erick Tryzelaar!)
+
+- Fixed end-of-string infinite looping on LineEnd and StringEnd
+  expressions.  (Thanks again to Erick Tryzelaar.)
+
+- Modified setWhitespaceChars to return self, to be consistent with
+  other ParserElement modifiers. (Suggested by Erick Tryzelaar.)
+
+- Fixed bug/typo in new ParseResults.dump() method.
+
+- Fixed bug in searchString() method, in which only the first token of
+  an expression was returned.  searchString() now returns a
+  ParseResults collection of all search matches.
+
+- Added example program removeLineBreaks.py, a string transformer that
+  converts text files with hard line-breaks into one with line breaks
+  only between paragraphs.
+
+- Added example program listAllMatches.py, to illustrate using the
+  listAllMatches option when specifying results names (also shows new
+  support for passing lists to oneOf).
+
+- Added example program linenoExample.py, to illustrate using the
+  helper methods lineno, line, and col, and returning objects from a
+  parse action.
+
+- Added example program parseListString.py, to which can parse the
+  string representation of a Python list back into a true list.  Taken
+  mostly from my PyCon presentation examples, but now with support
+  for tuple elements, too!
+
+
+
+Version 1.4.2 - April 1, 2006 (No foolin'!)
+-------------------------------------------
+- Significant speedup from memoizing nested expressions (a technique
+  known as "packrat parsing"), thanks to Chris Lesniewski-Laas!  Your
+  mileage may vary, but my Verilog parser almost doubled in speed to
+  over 600 lines/sec!
+
+  This speedup may break existing programs that use parse actions that
+  have side-effects.  For this reason, packrat parsing is disabled when
+  you first import pyparsing.  To activate the packrat feature, your
+  program must call the class method ParserElement.enablePackrat().  If
+  your program uses psyco to "compile as you go", you must call
+  enablePackrat before calling psyco.full().  If you do not do this,
+  Python will crash.  For best results, call enablePackrat() immediately
+  after importing pyparsing.
+
+- Added new helper method countedArray(expr), for defining patterns that
+  start with a leading integer to indicate the number of array elements,
+  followed by that many elements, matching the given expr parse
+  expression.  For instance, this two-liner:
+    wordArray = countedArray(Word(alphas))
+    print wordArray.parseString("3 Practicality beats purity")[0]
+  returns the parsed array of words:
+    ['Practicality', 'beats', 'purity']
+  The leading token '3' is suppressed, although it is easily obtained
+  from the length of the returned array.
+  (Inspired by e-mail discussion with Ralf Vosseler.)
+
+- Added support for attaching multiple parse actions to a single
+  ParserElement. (Suggested by Dan "Dang" Griffith - nice idea, Dan!)
+
+- Added support for asymmetric quoting characters in the recently-added
+  QuotedString class.  Now you can define your own quoted string syntax
+  like "<<This is a string in double angle brackets.>>".  To define
+  this custom form of QuotedString, your code would define:
+    dblAngleQuotedString = QuotedString('<<',endQuoteChar='>>')
+  QuotedString also supports escaped quotes, escape character other
+  than '\', and multiline.
+
+- Changed the default value returned internally by Optional, so that
+  None can be used as a default value.  (Suggested by Steven Bethard -
+  I finally saw the light!)
+
+- Added dump() method to ParseResults, to make it easier to list out
+  and diagnose values returned from calling parseString.
+
+- A new example, a search query string parser, submitted by Steven
+  Mooij and Rudolph Froger - a very interesting application, thanks!
+
+- Added an example that parses the BNF in Python's Grammar file, in
+  support of generating Python grammar documentation. (Suggested by
+  J H Stovall.)
+
+- A new example, submitted by Tim Cera, of a flexible parser module,
+  using a simple config variable to adjust parsing for input formats
+  that have slight variations - thanks, Tim!
+
+- Added an example for parsing Roman numerals, showing the capability
+  of parse actions to "compile" Roman numerals into their integer
+  values during parsing.
+
+- Added a new docs directory, for additional documentation or help.
+  Currently, this includes the text and examples from my recent
+  presentation at PyCon.
+
+- Fixed another typo in CaselessKeyword, thanks Stefan Behnel.
+
+- Expanded oneOf to also accept tuples, not just lists.  This really
+  should be sufficient...
+
+- Added deprecation warnings when tuple is returned from a parse action.
+  Looking back, I see that I originally deprecated this feature in March,
+  2004, so I'm guessing people really shouldn't have been using this
+  feature - I'll drop it altogether in the next release, which will
+  allow users to return a tuple from a parse action (which is really
+  handy when trying to reconstuct tuples from a tuple string
+  representation!).
+
+
+Version 1.4.1 - February, 2006
+------------------------------
+- Converted generator expression in QuotedString class to list
+  comprehension, to retain compatibility with Python 2.3. (Thanks, Titus
+  Brown for the heads-up!)
+
+- Added searchString() method to ParserElement, as an alternative to
+  using "scanString(instring).next()[0][0]" to search through a string
+  looking for a substring matching a given parse expression. (Inspired by
+  e-mail conversation with Dave Feustel.)
+
+- Modified oneOf to accept lists of strings as well as a single string
+  of space-delimited literals.  (Suggested by Jacek Sieka - thanks!)
+
+- Removed deprecated use of Upcase in pyparsing test code. (Also caught by
+  Titus Brown.)
+
+- Removed lstrip() call from Literal - too aggressive in stripping
+  whitespace which may be valid for some grammars.  (Point raised by Jacek
+  Sieka).  Also, made Literal more robust in the event of passing an empty
+  string.
+
+- Fixed bug in replaceWith when returning None.
+
+- Added cautionary documentation for Forward class when assigning a
+  MatchFirst expression, as in:
+    fwdExpr << a | b | c
+  Precedence of operators causes this to be evaluated as:
+    (fwdExpr << a) | b | c
+  thereby leaving b and c out as parseable alternatives.  Users must
+  explicitly group the values inserted into the Forward:
+    fwdExpr << (a | b | c)
+  (Suggested by Scot Wilcoxon - thanks, Scot!)
+
+
+Version 1.4 - January 18, 2006
+------------------------------
+- Added Regex class, to permit definition of complex embedded expressions
+  using regular expressions. (Enhancement provided by John Beisley, great
+  job!)
+
+- Converted implementations of Word, oneOf, quoted string, and comment
+  helpers to utilize regular expression matching.  Performance improvements
+  in the 20-40% range.
+
+- Added QuotedString class, to support definition of non-standard quoted
+  strings (Suggested by Guillaume Proulx, thanks!)
+
+- Added CaselessKeyword class, to streamline grammars with, well, caseless
+  keywords (Proposed by Stefan Behnel, thanks!)
+
+- Fixed bug in SkipTo, when using an ignoreable expression. (Patch provided
+  by Anonymous, thanks, whoever-you-are!)
+
+- Fixed typo in NoMatch class. (Good catch, Stefan Behnel!)
+
+- Fixed minor bug in _makeTags(), using string.printables instead of
+  pyparsing.printables.
+
+- Cleaned up some of the expressions created by makeXXXTags helpers, to
+  suppress extraneous <> characters.
+
+- Added some grammar definition-time checking to verify that a grammar is
+  being built using proper ParserElements.
+
+- Added examples:
+  . LAparser.py - linear algebra C preprocessor (submitted by Mike Ellis,
+    thanks Mike!)
+  . wordsToNum.py - converts word description of a number back to
+    the original number (such as 'one hundred and twenty three' -> 123)
+  . updated fourFn.py to support unary minus, added BNF comments
+
+
+Version 1.3.3 - September 12, 2005
+----------------------------------
+- Improved support for Unicode strings that would be returned using
+  srange.  Added greetingInKorean.py example, for a Korean version of
+  "Hello, World!" using Unicode. (Thanks, June Kim!)
+
+- Added 'hexnums' string constant (nums+"ABCDEFabcdef") for defining
+  hexadecimal value expressions.
+
+- NOTE: ===THIS CHANGE MAY BREAK EXISTING CODE===
+  Modified tag and results definitions returned by makeHTMLTags(),
+  to better support the looseness of HTML parsing.  Tags to be
+  parsed are now caseless, and keys generated for tag attributes are
+  now converted to lower case.
+
+  Formerly, makeXMLTags("XYZ") would return a tag with results
+  name of "startXYZ", this has been changed to "startXyz".  If this
+  tag is matched against '<XYZ Abc="1" DEF="2" ghi="3">', the
+  matched keys formerly would be "Abc", "DEF", and "ghi"; keys are
+  now converted to lower case, giving keys of "abc", "def", and
+  "ghi".  These changes were made to try to address the lax
+  case sensitivity agreement between start and end tags in many
+  HTML pages.
+
+  No changes were made to makeXMLTags(), which assumes more rigorous
+  parsing rules.
+
+  Also, cleaned up case-sensitivity bugs in closing tags, and
+  switched to using Keyword instead of Literal class for tags.
+  (Thanks, Steve Young, for getting me to look at these in more
+  detail!)
+
+- Added two helper parse actions, upcaseTokens and downcaseTokens,
+  which will convert matched text to all uppercase or lowercase,
+  respectively.
+
+- Deprecated Upcase class, to be replaced by upcaseTokens parse
+  action.
+
+- Converted messages sent to stderr to use warnings module, such as
+  when constructing a Literal with an empty string, one should use
+  the Empty() class or the empty helper instead.
+
+- Added ' ' (space) as an escapable character within a quoted
+  string.
+
+- Added helper expressions for common comment types, in addition
+  to the existing cStyleComment (/*...*/) and htmlStyleComment
+  (<!-- ... -->)
+  . dblSlashComment = // ... (to end of line)
+  . cppStyleComment = cStyleComment or dblSlashComment
+  . javaStyleComment = cppStyleComment
+  . pythonStyleComment = # ... (to end of line)
+
+
+
+Version 1.3.2 - July 24, 2005
+-----------------------------
+- Added Each class as an enhanced version of And.  'Each' requires
+  that all given expressions be present, but may occur in any order.
+  Special handling is provided to group ZeroOrMore and OneOrMore
+  elements that occur out-of-order in the input string.  You can also
+  construct 'Each' objects by joining expressions with the '&'
+  operator.  When using the Each class, results names are strongly
+  recommended for accessing the matched tokens. (Suggested by Pradam
+  Amini - thanks, Pradam!)
+
+- Stricter interpretation of 'max' qualifier on Word elements.  If the
+  'max' attribute is specified, matching will fail if an input field
+  contains more than 'max' consecutive body characters.  For example,
+  previously, Word(nums,max=3) would match the first three characters
+  of '0123456', returning '012' and continuing parsing at '3'.  Now,
+  when constructed using the max attribute, Word will raise an
+  exception with this string.
+
+- Cleaner handling of nested dictionaries returned by Dict.  No
+  longer necessary to dereference sub-dictionaries as element [0] of
+  their parents.
+  === NOTE: THIS CHANGE MAY BREAK SOME EXISTING CODE, BUT ONLY IF
+  PARSING NESTED DICTIONARIES USING THE LITTLE-USED DICT CLASS ===
+  (Prompted by discussion thread on the Python Tutor list, with
+  contributions from Danny Yoo, Kent Johnson, and original post by
+  Liam Clarke - thanks all!)
+
+
+
+Version 1.3.1 - June, 2005
+----------------------------------
+- Added markInputline() method to ParseException, to display the input
+  text line location of the parsing exception. (Thanks, Stefan Behnel!)
+
+- Added setDefaultKeywordChars(), so that Keyword definitions using a
+  custom keyword character set do not all need to add the keywordChars
+  constructor argument (similar to setDefaultWhitespaceChars()).
+  (suggested by rzhanka on the SourceForge pyparsing forum.)
+
+- Simplified passing debug actions to setDebugAction().  You can now
+  pass 'None' for a debug action if you want to take the default
+  debug behavior.  To suppress a particular debug action, you can pass
+  the pyparsing method nullDebugAction.
+
+- Refactored parse exception classes, moved all behavior to
+  ParseBaseException, and the former ParseException is now a subclass of
+  ParseBaseException.  Added a second subclass, ParseFatalException, as
+  a subclass of ParseBaseException.  User-defined parse actions can raise
+  ParseFatalException if a data inconsistency is detected (such as a
+  begin-tag/end-tag mismatch), and this will stop all parsing immediately.
+  (Inspired by e-mail thread with Michele Petrazzo - thanks, Michelle!)
+
+- Added helper methods makeXMLTags and makeHTMLTags, that simplify the
+  definition of XML or HTML tag parse expressions for a given tagname.
+  Both functions return a pair of parse expressions, one for the opening
+  tag (that is, '<tagname>') and one for the closing tag ('</tagname>').
+  The opening tagame also recognizes any attribute definitions that have
+  been included in the opening tag, as well as an empty tag (one with a
+  trailing '/', as in '<BODY/>' which is equivalent to '<BODY></BODY>').
+  makeXMLTags uses stricter XML syntax for attributes, requiring that they
+  be enclosed in double quote characters - makeHTMLTags is more lenient,
+  and accepts single-quoted strings or any contiguous string of characters
+  up to the next whitespace character or '>' character.  Attributes can
+  be retrieved as dictionary or attribute values of the returned results
+  from the opening tag.
+
+- Added example minimath2.py, a refinement on fourFn.py that adds
+  an interactive session and support for variables.  (Thanks, Steven Siew!)
+
+- Added performance improvement, up to 20% reduction!  (Found while working
+  with Wolfgang Borgert on performance tuning of his TTCN3 parser.)
+
+- And another performance improvement, up to 25%, when using scanString!
+  (Found while working with Henrik Westlund on his C header file scanner.)
+
+- Updated UML diagrams to reflect latest class/method changes.
+
+
+Version 1.3 - March, 2005
+----------------------------------
+- Added new Keyword class, as a special form of Literal.  Keywords
+  must be followed by whitespace or other non-keyword characters, to
+  distinguish them from variables or other identifiers that just
+  happen to start with the same characters as a keyword.  For instance,
+  the input string containing "ifOnlyIfOnly" will match a Literal("if")
+  at the beginning and in the middle, but will fail to match a
+  Keyword("if").  Keyword("if") will match only strings such as "if only"
+  or "if(only)". (Proposed by Wolfgang Borgert, and Berteun Damman
+  separately requested this on comp.lang.python - great idea!)
+
+- Added setWhitespaceChars() method to override the characters to be
+  skipped as whitespace before matching a particular ParseElement.  Also
+  added the class-level method setDefaultWhitespaceChars(), to allow
+  users to override the default set of whitespace characters (space,
+  tab, newline, and return) for all subsequently defined ParseElements.
+  (Inspired by Klaas Hofstra's inquiry on the Sourceforge pyparsing
+  forum.)
+
+- Added helper parse actions to support some very common parse
+  action use cases:
+  . replaceWith(replStr) - replaces the matching tokens with the
+    provided replStr replacement string; especially useful with
+    transformString()
+  . removeQuotes - removes first and last character from string enclosed
+    in quotes (note - NOT the same as the string strip() method, as only
+    a single character is removed at each end)
+
+- Added copy() method to ParseElement, to make it easier to define
+  different parse actions for the same basic parse expression.  (Note, copy
+  is implicitly called when using setResultsName().)
+
+
+  (The following changes were posted to CVS as Version 1.2.3 -
+  October-December, 2004)
+
+- Added support for Unicode strings in creating grammar definitions.
+  (Big thanks to Gavin Panella!)
+
+- Added constant alphas8bit to include the following 8-bit characters:
+    �������������������������������������������������������������
+
+- Added srange() function to simplify definition of Word elements, using
+  regexp-like '[A-Za-z0-9]' syntax.  This also simplifies referencing
+  common 8-bit characters.
+
+- Fixed bug in Dict when a single element Dict was embedded within another
+  Dict. (Thanks Andy Yates for catching this one!)
+
+- Added 'formatted' argument to ParseResults.asXML().  If set to False,
+  suppresses insertion of whitespace for pretty-print formatting.  Default
+  equals True for backward compatibility.
+
+- Added setDebugActions() function to ParserElement, to allow user-defined
+  debugging actions.
+
+- Added support for escaped quotes (either in \', \", or doubled quote
+  form) to the predefined expressions for quoted strings. (Thanks, Ero
+  Carrera!)
+
+- Minor performance improvement (~5%) converting "char in string" tests
+  to "char in dict". (Suggested by Gavin Panella, cool idea!)
+
+
+Version 1.2.2 - September 27, 2004
+----------------------------------
+- Modified delimitedList to accept an expression as the delimiter, instead
+  of only accepting strings.
+
+- Modified ParseResults, to convert integer field keys to strings (to
+  avoid confusion with list access).
+
+- Modified Combine, to convert all embedded tokens to strings before
+  combining.
+
+- Fixed bug in MatchFirst in which parse actions would be called for
+  expressions that only partially match. (Thanks, John Hunter!)
+
+- Fixed bug in fourFn.py example that fixes right-associativity of ^
+  operator. (Thanks, Andrea Griffini!)
+
+- Added class FollowedBy(expression), to look ahead in the input string
+  without consuming tokens.
+
+- Added class NoMatch that never matches any input. Can be useful in
+  debugging, and in very specialized grammars.
+
+- Added example pgn.py, for parsing chess game files stored in Portable
+  Game Notation. (Thanks, Alberto Santini!)
+
+
+Version 1.2.1 - August 19, 2004
+-------------------------------
+- Added SkipTo(expression) token type, simplifying grammars that only
+  want to specify delimiting expressions, and want to match any characters
+  between them.
+
+- Added helper method dictOf(key,value), making it easier to work with
+  the Dict class. (Inspired by Pavel Volkovitskiy, thanks!).
+
+- Added optional argument listAllMatches (default=False) to
+  setResultsName().  Setting listAllMatches to True overrides the default
+  modal setting of tokens to results names; instead, the results name
+  acts as an accumulator for all matching tokens within the local
+  repetition group. (Suggested by Amaury Le Leyzour - thanks!)
+
+- Fixed bug in ParseResults, throwing exception when trying to extract
+  slice, or make a copy using [:]. (Thanks, Wilson Fowlie!)
+
+- Fixed bug in transformString() when the input string contains <TAB>'s
+  (Thanks, Rick Walia!).
+
+- Fixed bug in returning tokens from un-Grouped And's, Or's and
+  MatchFirst's, where too many tokens would be included in the results,
+  confounding parse actions and returned results.
+
+- Fixed bug in naming ParseResults returned by And's, Or's, and Match
+  First's.
+
+- Fixed bug in LineEnd() - matching this token now correctly consumes
+  and returns the end of line "\n".
+
+- Added a beautiful example for parsing Mozilla calendar files (Thanks,
+  Petri Savolainen!).
+
+- Added support for dynamically modifying Forward expressions during
+  parsing.
+
+
+Version 1.2 - 20 June 2004
+--------------------------
+- Added definition for htmlComment to help support HTML scanning and
+  parsing.
+
+- Fixed bug in generating XML for Dict classes, in which trailing item was
+  duplicated in the output XML.
+
+- Fixed release bug in which scanExamples.py was omitted from release
+  files.
+
+- Fixed bug in transformString() when parse actions are not defined on the
+  outermost parser element.
+
+- Added example urlExtractor.py, as another example of using scanString
+  and parse actions.
+
+
+Version 1.2beta3 - 4 June 2004
+------------------------------
+- Added White() token type, analogous to Word, to match on whitespace
+  characters.  Use White in parsers with significant whitespace (such as
+  configuration file parsers that use indentation to indicate grouping).
+  Construct White with a string containing the whitespace characters to be
+  matched.  Similar to Word, White also takes optional min, max, and exact
+  parameters.
+
+- As part of supporting whitespace-signficant parsing, added parseWithTabs()
+  method to ParserElement, to override the default behavior in parseString
+  of automatically expanding tabs to spaces.  To retain tabs during
+  parsing, call parseWithTabs() before calling parseString(), parseFile() or
+  scanString(). (Thanks, Jean-Guillaume Paradis for catching this, and for
+  your suggestions on whitespace-significant parsing.)
+
+- Added transformString() method to ParseElement, as a complement to
+  scanString().  To use transformString, define a grammar and attach a parse
+  action to the overall grammar that modifies the returned token list.
+  Invoking transformString() on a target string will then scan for matches,
+  and replace the matched text patterns according to the logic in the parse
+  action.  transformString() returns the resulting transformed string.
+  (Note: transformString() does *not* automatically expand tabs to spaces.)
+  Also added scanExamples.py to the examples directory to show sample uses of
+  scanString() and transformString().
+
+- Removed group() method that was introduced in beta2.  This turns out NOT to
+  be equivalent to nesting within a Group() object, and I'd prefer not to sow
+  more seeds of confusion.
+
+- Fixed behavior of asXML() where tags for groups were incorrectly duplicated.
+  (Thanks, Brad Clements!)
+
+- Changed beta version message to display to stderr instead of stdout, to
+  make asXML() easier to use.  (Thanks again, Brad.)
+
+
+Version 1.2beta2 - 19 May 2004
+------------------------------
+- *** SIMPLIFIED API *** - Parse actions that do not modify the list of tokens
+  no longer need to return a value.  This simplifies those parse actions that
+  use the list of tokens to update a counter or record or display some of the
+  token content; these parse actions can simply end without having to specify
+  'return toks'.
+
+- *** POSSIBLE API INCOMPATIBILITY *** - Fixed CaselessLiteral bug, where the
+  returned token text was not the original string (as stated in the docs),
+  but the original string converted to upper case.  (Thanks, Dang Griffith!)
+  **NOTE: this may break some code that relied on this erroneous behavior.
+  Users should scan their code for uses of CaselessLiteral.**
+
+- *** POSSIBLE CODE INCOMPATIBILITY *** - I have renamed the internal
+  attributes on ParseResults from 'dict' and 'list' to '__tokdict' and
+  '__toklist', to avoid collisions with user-defined data fields named 'dict'
+  and 'list'.  Any client code that accesses these attributes directly will
+  need to be modified.  Hopefully the implementation of methods such as keys(),
+  items(), len(), etc. on ParseResults will make such direct attribute
+  accessess unnecessary.
+
+- Added asXML() method to ParseResults.  This greatly simplifies the process
+  of parsing an input data file and generating XML-structured data.
+
+- Added getName() method to ParseResults.  This method is helpful when
+  a grammar specifies ZeroOrMore or OneOrMore of a MatchFirst or Or
+  expression, and the parsing code needs to know which expression matched.
+  (Thanks, Eric van der Vlist, for this idea!)
+
+- Added items() and values() methods to ParseResults, to better support using
+  ParseResults as a Dictionary.
+
+- Added parseFile() as a convenience function to parse the contents of an
+  entire text file.  Accepts either a file name or a file object.  (Thanks
+  again, Dang!)
+
+- Added group() method to And, Or, and MatchFirst, as a short-cut alternative
+  to enclosing a construct inside a Group object.
+
+- Extended fourFn.py to support exponentiation, and simple built-in functions.
+
+- Added EBNF parser to examples, including a demo where it parses its own
+  EBNF!  (Thanks to Seo Sanghyeon!)
+
+- Added Delphi Form parser to examples, dfmparse.py, plus a couple of
+  sample Delphi forms as tests.  (Well done, Dang!)
+
+- Another performance speedup, 5-10%, inspired by Dang!  Plus about a 20%
+  speedup, by pre-constructing and cacheing exception objects instead of
+  constructing them on the fly.
+
+- Fixed minor bug when specifying oneOf() with 'caseless=True'.
+
+- Cleaned up and added a few more docstrings, to improve the generated docs.
+
+
+Version 1.1.2 - 21 Mar 2004
+---------------------------
+- Fixed minor bug in scanString(), so that start location is at the start of
+  the matched tokens, not at the start of the whitespace before the matched
+  tokens.
+
+- Inclusion of HTML documentation, generated using Epydoc.  Reformatted some
+  doc strings to better generate readable docs. (Beautiful work, Ed Loper,
+  thanks for Epydoc!)
+
+- Minor performance speedup, 5-15%
+
+- And on a process note, I've used the unittest module to define a series of
+  unit tests, to help avoid the embarrassment of the version 1.1 snafu.
+
+
+Version 1.1.1 - 6 Mar 2004
+--------------------------
+- Fixed critical bug introduced in 1.1, which broke MatchFirst(!) token
+  matching.
+  **THANK YOU, SEO SANGHYEON!!!**
+
+- Added "from future import __generators__" to permit running under
+  pre-Python 2.3.
+
+- Added example getNTPservers.py, showing how to use pyparsing to extract
+  a text pattern from the HTML of a web page.
+
+
+Version 1.1 - 3 Mar 2004
+-------------------------
+- ***Changed API*** - While testing out parse actions, I found that the value
+  of loc passed in was not the starting location of the matched tokens, but
+  the location of the next token in the list.  With this version, the location
+  passed to the parse action is now the starting location of the tokens that
+  matched.
+
+  A second part of this change is that the return value of parse actions no
+  longer needs to return a tuple containing both the location and the parsed
+  tokens (which may optionally be modified); parse actions only need to return
+  the list of tokens.  Parse actions that return a tuple are deprecated; they
+  will still work properly for conversion/compatibility, but this behavior will
+  be removed in a future version.
+
+- Added validate() method, to help diagnose infinite recursion in a grammar tree.
+  validate() is not 100% fool-proof, but it can help track down nasty infinite
+  looping due to recursively referencing the same grammar construct without some
+  intervening characters.
+
+- Cleaned up default listing of some parse element types, to more closely match
+  ordinary BNF.  Instead of the form <classname>:[contents-list], some changes
+  are:
+  . And(token1,token2,token3) is "{ token1 token2 token3 }"
+  . Or(token1,token2,token3) is "{ token1 ^ token2 ^ token3 }"
+  . MatchFirst(token1,token2,token3) is "{ token1 | token2 | token3 }"
+  . Optional(token) is "[ token ]"
+  . OneOrMore(token) is "{ token }..."
+  . ZeroOrMore(token) is "[ token ]..."
+
+- Fixed an infinite loop in oneOf if the input string contains a duplicated
+  option. (Thanks Brad Clements)
+
+- Fixed a bug when specifying a results name on an Optional token. (Thanks
+  again, Brad Clements)
+
+- Fixed a bug introduced in 1.0.6 when I converted quotedString to use
+  CharsNotIn; I accidentally permitted quoted strings to span newlines.  I have
+  fixed this in this version to go back to the original behavior, in which
+  quoted strings do *not* span newlines.
+
+- Fixed minor bug in HTTP server log parser. (Thanks Jim Richardson)
+
+
+Version 1.0.6 -  13 Feb 2004
+----------------------------
+- Added CharsNotIn class (Thanks, Lee SangYeong).  This is the opposite of
+  Word, in that it is constructed with a set of characters *not* to be matched.
+  (This enhancement also allowed me to clean up and simplify some of the
+  definitions for quoted strings, cStyleComment, and restOfLine.)
+
+- **MINOR API CHANGE** - Added joinString argument to the __init__ method of
+  Combine (Thanks, Thomas Kalka).  joinString defaults to "", but some
+  applications might choose some other string to use instead, such as a blank
+  or newline.  joinString was inserted as the second argument to __init__,
+  so if you have code that specifies an adjacent value, without using
+  'adjacent=', this code will break.
+
+- Modified LineStart to recognize the start of an empty line.
+
+- Added optional caseless flag to oneOf(), to create a list of CaselessLiteral
+  tokens instead of Literal tokens.
+
+- Added some enhancements to the SQL example:
+  . Oracle-style comments (Thanks to Harald Armin Massa)
+  . simple WHERE clause
+
+- Minor performance speedup - 5-15%
+
+
+Version 1.0.5 -  19 Jan 2004
+----------------------------
+- Added scanString() generator method to ParseElement, to support regex-like
+  pattern-searching
+
+- Added items() list to ParseResults, to return named results as a
+  list of (key,value) pairs
+
+- Fixed memory overflow in asList() for deeply nested ParseResults (Thanks,
+  Sverrir Valgeirsson)
+
+- Minor performance speedup - 10-15%
+
+
+Version 1.0.4 -  8 Jan 2004
+---------------------------
+- Added positional tokens StringStart, StringEnd, LineStart, and LineEnd
+
+- Added commaSeparatedList to pre-defined global token definitions; also added
+  commasep.py to the examples directory, to demonstrate the differences between
+  parsing comma-separated data and simple line-splitting at commas
+
+- Minor API change: delimitedList does not automatically enclose the
+  list elements in a Group, but makes this the responsibility of the caller;
+  also, if invoked using 'combine=True', the list delimiters are also included
+  in the returned text (good for scoped variables, such as a.b.c or a::b::c, or
+  for directory paths such as a/b/c)
+
+- Performance speed-up again, 30-40%
+
+- Added httpServerLogParser.py to examples directory, as this is
+  a common parsing task
+
+
+Version 1.0.3 - 23 Dec 2003
+---------------------------
+- Performance speed-up again, 20-40%
+
+- Added Python distutils installation setup.py, etc. (thanks, Dave Kuhlman)
+
+
+Version 1.0.2 - 18 Dec 2003
+---------------------------
+- **NOTE: Changed API again!!!** (for the last time, I hope)
+
+  + Renamed module from parsing to pyparsing, to better reflect Python
+    linkage.
+
+- Also added dictExample.py to examples directory, to illustrate
+  usage of the Dict class.
+
+
+Version 1.0.1 - 17 Dec 2003
+---------------------------
+- **NOTE:  Changed API!**
+
+  + Renamed 'len' argument on Word.__init__() to 'exact'
+
+- Performance speed-up, 10-30%
+
+
+Version 1.0.0 - 15 Dec 2003
+---------------------------
+- Initial public release
+
+Version 0.1.1 thru 0.1.17 - October-November, 2003
+--------------------------------------------------
+- initial development iterations:
+    - added Dict, Group
+    - added helper methods oneOf, delimitedList
+    - added helpers quotedString (and double and single), restOfLine, cStyleComment
+    - added MatchFirst as an alternative to the slower Or
+    - added UML class diagram
+    - fixed various logic bugs
diff --git a/HowToUsePyparsing.html b/HowToUsePyparsing.html
new file mode 100644
--- /dev/null
+++ b/HowToUsePyparsing.html
@@ -0,0 +1,1284 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
+<title>Using the pyparsing module</title>
+<meta name="author" content="Paul McGuire" />
+<meta name="date" content="October, 2008" />
+<meta name="copyright" content="Copyright © 2003-2008 Paul McGuire." />
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 5196 2007-06-03 20:25:28Z wiemann $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+ul.auto-toc {
+  list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="using-the-pyparsing-module">
+<h1 class="title">Using the pyparsing module</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>Paul McGuire</td></tr>
+<tr><th class="docinfo-name">Address:</th>
+<td><pre class="address">
+<a class="first last reference external" href="mailto:ptmcg&#64;users.sourceforge.net">ptmcg&#64;users.sourceforge.net</a>
+</pre>
+</td></tr>
+<tr><th class="docinfo-name">Revision:</th>
+<td>1.5.1</td></tr>
+<tr><th class="docinfo-name">Date:</th>
+<td>October, 2008</td></tr>
+<tr><th class="docinfo-name">Copyright:</th>
+<td>Copyright © 2003-2008 Paul McGuire.</td></tr>
+</tbody>
+</table>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">abstract:</th><td class="field-body">This document provides how-to instructions for the
+pyparsing library, an easy-to-use Python module for constructing
+and executing basic text parsers.  The pyparsing module is useful
+for evaluating user-definable
+expressions, processing custom application language commands, or
+extracting data from formatted reports.</td>
+</tr>
+</tbody>
+</table>
+<div class="contents topic" id="contents">
+<p class="topic-title first">Contents</p>
+<ul class="auto-toc simple">
+<li><a class="reference internal" href="#steps-to-follow" id="id1">1&nbsp;&nbsp;&nbsp;Steps to follow</a><ul class="auto-toc">
+<li><a class="reference internal" href="#hello-world" id="id2">1.1&nbsp;&nbsp;&nbsp;Hello, World!</a></li>
+<li><a class="reference internal" href="#new-features-in-1-5-1" id="id3">1.2&nbsp;&nbsp;&nbsp;New features in 1.5.1</a></li>
+<li><a class="reference internal" href="#new-features-in-1-5-0" id="id4">1.3&nbsp;&nbsp;&nbsp;New features in 1.5.0</a></li>
+<li><a class="reference internal" href="#usage-notes" id="id5">1.4&nbsp;&nbsp;&nbsp;Usage notes</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#classes" id="id6">2&nbsp;&nbsp;&nbsp;Classes</a><ul class="auto-toc">
+<li><a class="reference internal" href="#classes-in-the-pyparsing-module" id="id7">2.1&nbsp;&nbsp;&nbsp;Classes in the pyparsing module</a></li>
+<li><a class="reference internal" href="#basic-parserelement-subclasses" id="id8">2.2&nbsp;&nbsp;&nbsp;Basic ParserElement subclasses</a></li>
+<li><a class="reference internal" href="#expression-subclasses" id="id9">2.3&nbsp;&nbsp;&nbsp;Expression subclasses</a></li>
+<li><a class="reference internal" href="#expression-operators" id="id10">2.4&nbsp;&nbsp;&nbsp;Expression operators</a></li>
+<li><a class="reference internal" href="#positional-subclasses" id="id11">2.5&nbsp;&nbsp;&nbsp;Positional subclasses</a></li>
+<li><a class="reference internal" href="#converter-subclasses" id="id12">2.6&nbsp;&nbsp;&nbsp;Converter subclasses</a></li>
+<li><a class="reference internal" href="#special-subclasses" id="id13">2.7&nbsp;&nbsp;&nbsp;Special subclasses</a></li>
+<li><a class="reference internal" href="#other-classes" id="id14">2.8&nbsp;&nbsp;&nbsp;Other classes</a></li>
+<li><a class="reference internal" href="#exception-classes-and-troubleshooting" id="id15">2.9&nbsp;&nbsp;&nbsp;Exception classes and Troubleshooting</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#miscellaneous-attributes-and-methods" id="id16">3&nbsp;&nbsp;&nbsp;Miscellaneous attributes and methods</a><ul class="auto-toc">
+<li><a class="reference internal" href="#helper-methods" id="id17">3.1&nbsp;&nbsp;&nbsp;Helper methods</a></li>
+<li><a class="reference internal" href="#helper-parse-actions" id="id18">3.2&nbsp;&nbsp;&nbsp;Helper parse actions</a></li>
+<li><a class="reference internal" href="#common-string-and-token-constants" id="id19">3.3&nbsp;&nbsp;&nbsp;Common string and token constants</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="steps-to-follow">
+<h1><a class="toc-backref" href="#id1">1&nbsp;&nbsp;&nbsp;Steps to follow</a></h1>
+<p>To parse an incoming data string, the client code must follow these steps:</p>
+<ol class="arabic simple">
+<li>First define the tokens and patterns to be matched, and assign
+this to a program variable.  Optional results names or parsing
+actions can also be defined at this time.</li>
+<li>Call <tt class="docutils literal"><span class="pre">parseString()</span></tt> or <tt class="docutils literal"><span class="pre">scanString()</span></tt> on this variable, passing in
+the string to
+be parsed.  During the matching process, whitespace between
+tokens is skipped by default (although this can be changed).
+When token matches occur, any defined parse action methods are
+called.</li>
+<li>Process the parsed results, returned as a list of strings.
+Matching results may also be accessed as named attributes of
+the returned results, if names are defined in the definition of
+the token pattern, using <tt class="docutils literal"><span class="pre">setResultsName()</span></tt>.</li>
+</ol>
+<div class="section" id="hello-world">
+<h2><a class="toc-backref" href="#id2">1.1&nbsp;&nbsp;&nbsp;Hello, World!</a></h2>
+<p>The following complete Python program will parse the greeting &quot;Hello, World!&quot;,
+or any other greeting of the form &quot;&lt;salutation&gt;, &lt;addressee&gt;!&quot;:</p>
+<pre class="literal-block">
+from pyparsing import Word, alphas
+
+greet = Word( alphas ) + &quot;,&quot; + Word( alphas ) + &quot;!&quot;
+greeting = greet.parseString( &quot;Hello, World!&quot; )
+print greeting
+</pre>
+<p>The parsed tokens are returned in the following form:</p>
+<pre class="literal-block">
+['Hello', ',', 'World', '!']
+</pre>
+</div>
+<div class="section" id="new-features-in-1-5-1">
+<h2><a class="toc-backref" href="#id3">1.2&nbsp;&nbsp;&nbsp;New features in 1.5.1</a></h2>
+<p>Some of the significant features added in version 1.5.0 are:</p>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">originalTextFor</span></tt> helper method, to simplify grammar expressions that need to preserve
+the original input text; should be used in place of the <tt class="docutils literal"><span class="pre">keepOriginalText</span></tt> parse action:</p>
+<pre class="literal-block">
+fullName = Word(alphas) + Word(alphas)
+fullName.setParseAction(keepOriginalText)
+</pre>
+<p>should now be written:</p>
+<pre class="literal-block">
+fullName = originalTextFor(Word(alphas) + Word(alphas))
+</pre>
+</li>
+<li><p class="first">added parameter <tt class="docutils literal"><span class="pre">parseAll</span></tt> to <tt class="docutils literal"><span class="pre">ParserElement.parseFile</span></tt> to
+match the arguments for <tt class="docutils literal"><span class="pre">ParserElement.parseString</span></tt></p>
+</li>
+<li><p class="first">new argument <tt class="docutils literal"><span class="pre">failOn</span></tt> for SkipTo expressions, to define literal strings or expressions that
+should not be included in the skipped text</p>
+</li>
+</ul>
+</div>
+<div class="section" id="new-features-in-1-5-0">
+<h2><a class="toc-backref" href="#id4">1.3&nbsp;&nbsp;&nbsp;New features in 1.5.0</a></h2>
+<p>Some of the significant features added in version 1.5.0 are:</p>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">indentedBlock</span></tt> helper method to define grammars using block indentation for grouping (like Python)</li>
+<li>new parameter <tt class="docutils literal"><span class="pre">parseAll</span></tt> in <tt class="docutils literal"><span class="pre">ParserElement.parseString</span></tt></li>
+<li>operator '-' for combining ParserElements; similar to the '+' operator, but raises an immediate
+<tt class="docutils literal"><span class="pre">ParseSyntaxException</span></tt> if an expression after the '-' operator fails to match; using '-' can
+provide error messages that are more useful for application users to find syntax errors in their
+input text</li>
+</ul>
+</div>
+<div class="section" id="usage-notes">
+<h2><a class="toc-backref" href="#id5">1.4&nbsp;&nbsp;&nbsp;Usage notes</a></h2>
+<ul>
+<li><p class="first">The pyparsing module can be used to interpret simple command
+strings or algebraic expressions, or can be used to extract data
+from text reports with complicated format and structure (&quot;screen
+or report scraping&quot;).  However, it is possible that your defined
+matching patterns may accept invalid inputs.  Use pyparsing to
+extract data from strings assumed to be well-formatted.</p>
+</li>
+<li><p class="first">To keep up the readability of your code, use <a class="reference internal" href="#operators">operators</a>  such as <tt class="docutils literal"><span class="pre">+</span></tt>, <tt class="docutils literal"><span class="pre">|</span></tt>,
+<tt class="docutils literal"><span class="pre">^</span></tt>, and <tt class="docutils literal"><span class="pre">~</span></tt> to combine expressions.  You can also combine
+string literals with ParseExpressions - they will be
+automatically converted to Literal objects.  For example:</p>
+<pre class="literal-block">
+integer  = Word( nums )            # simple unsigned integer
+variable = Word( alphas, max=1 )   # single letter variable, such as x, z, m, etc.
+arithOp  = Word( &quot;+-*/&quot;, max=1 )   # arithmetic operators
+equation = variable + &quot;=&quot; + integer + arithOp + integer    # will match &quot;x=2+2&quot;, etc.
+</pre>
+<p>In the definition of <tt class="docutils literal"><span class="pre">equation</span></tt>, the string <tt class="docutils literal"><span class="pre">&quot;=&quot;</span></tt> will get added as
+a <tt class="docutils literal"><span class="pre">Literal(&quot;=&quot;)</span></tt>, but in a more readable way.</p>
+</li>
+<li><p class="first">The pyparsing module's default behavior is to ignore whitespace.  This is the
+case for 99% of all parsers ever written.  This allows you to write simple, clean,
+grammars, such as the above <tt class="docutils literal"><span class="pre">equation</span></tt>, without having to clutter it up with
+extraneous <tt class="docutils literal"><span class="pre">ws</span></tt> markers.  The <tt class="docutils literal"><span class="pre">equation</span></tt> grammar will successfully parse all of the
+following statements:</p>
+<pre class="literal-block">
+x=2+2
+x = 2+2
+a = 10   *   4
+r= 1234/ 100000
+</pre>
+<p>Of course, it is quite simple to extend this example to support more elaborate expressions, with
+nesting with parentheses, floating point numbers, scientific notation, and named constants
+(such as <tt class="docutils literal"><span class="pre">e</span></tt> or <tt class="docutils literal"><span class="pre">pi</span></tt>).  See <tt class="docutils literal"><span class="pre">fourFn.py</span></tt>, included in the examples directory.</p>
+</li>
+<li><p class="first">To modify pyparsing's default whitespace skipping, you can use one or
+more of the following methods:</p>
+<ul>
+<li><p class="first">use the static method <tt class="docutils literal"><span class="pre">ParserElement.setDefaultWhitespaceChars</span></tt>
+to override the normal set of whitespace chars (' tn').  For instance
+when defining a grammar in which newlines are significant, you should
+call <tt class="docutils literal"><span class="pre">ParserElement.setDefaultWhitespaceChars('</span> <span class="pre">\t')</span></tt> to remove
+newline from the set of skippable whitespace characters.  Calling
+this method will affect all pyparsing expressions defined afterward.</p>
+</li>
+<li><p class="first">call <tt class="docutils literal"><span class="pre">leaveWhitespace()</span></tt> on individual expressions, to suppress the
+skipping of whitespace before trying to match the expression</p>
+</li>
+<li><p class="first">use <tt class="docutils literal"><span class="pre">Combine</span></tt> to require that successive expressions must be
+adjacent in the input string.  For instance, this expression:</p>
+<pre class="literal-block">
+real = Word(nums) + '.' + Word(nums)
+</pre>
+<p>will match &quot;3.14159&quot;, but will also match &quot;3 . 12&quot;.  It will also
+return the matched results as ['3', '.', '14159'].  By changing this
+expression to:</p>
+<pre class="literal-block">
+real = Combine( Word(nums) + '.' + Word(nums) )
+</pre>
+<p>it will not match numbers with embedded spaces, and it will return a
+single concatenated string '3.14159' as the parsed token.</p>
+</li>
+</ul>
+</li>
+<li><p class="first">Repetition of expressions can be indicated using the '*' operator.  An
+expression may be multiplied by an integer value (to indicate an exact
+repetition count), or by a tuple containing
+two integers, or None and an integer, representing min and max repetitions
+(with None representing no min or no max, depending whether it is the first or
+second tuple element).  See the following examples, where n is used to
+indicate an integer value:</p>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">expr*3</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">expr</span> <span class="pre">+</span> <span class="pre">expr</span> <span class="pre">+</span> <span class="pre">expr</span></tt></li>
+<li><tt class="docutils literal"><span class="pre">expr*(2,3)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">expr</span> <span class="pre">+</span> <span class="pre">expr</span> <span class="pre">+</span> <span class="pre">Optional(expr)</span></tt></li>
+<li><tt class="docutils literal"><span class="pre">expr*(n,None)</span></tt> or <tt class="docutils literal"><span class="pre">expr*(n,)</span></tt> is equivalent
+to <tt class="docutils literal"><span class="pre">expr*n</span> <span class="pre">+</span> <span class="pre">ZeroOrMore(expr)</span></tt> (read as &quot;at least n instances of expr&quot;)</li>
+<li><tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">expr*(0,n)</span></tt>
+(read as &quot;0 to n instances of expr&quot;)</li>
+<li><tt class="docutils literal"><span class="pre">expr*(None,None)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">ZeroOrMore(expr)</span></tt></li>
+<li><tt class="docutils literal"><span class="pre">expr*(1,None)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">OneOrMore(expr)</span></tt></li>
+</ul>
+<p>Note that <tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> does not raise an exception if
+more than n exprs exist in the input stream; that is,
+<tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> does not enforce a maximum number of expr
+occurrences.  If this behavior is desired, then write
+<tt class="docutils literal"><span class="pre">expr*(None,n)</span> <span class="pre">+</span> <span class="pre">~expr</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">MatchFirst</span></tt> expressions are matched left-to-right, and the first
+match found will skip all later expressions within, so be sure
+to define less-specific patterns after more-specific patterns.
+If you are not sure which expressions are most specific, use Or
+expressions (defined using the <tt class="docutils literal"><span class="pre">^</span></tt> operator) - they will always
+match the longest expression, although they are more
+compute-intensive.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Or</span></tt> expressions will evaluate all of the specified subexpressions
+to determine which is the &quot;best&quot; match, that is, which matches
+the longest string in the input data.  In case of a tie, the
+left-most expression in the <tt class="docutils literal"><span class="pre">Or</span></tt> list will win.</p>
+</li>
+<li><p class="first">If parsing the contents of an entire file, pass it to the
+<tt class="docutils literal"><span class="pre">parseFile</span></tt> method using:</p>
+<pre class="literal-block">
+expr.parseFile( sourceFile )
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">ParseExceptions</span></tt> will report the location where an expected token
+or expression failed to match.  For example, if we tried to use our
+&quot;Hello, World!&quot; parser to parse &quot;Hello World!&quot; (leaving out the separating
+comma), we would get an exception, with the message:</p>
+<pre class="literal-block">
+pyparsing.ParseException: Expected &quot;,&quot; (6), (1,7)
+</pre>
+<p>In the case of complex
+expressions, the reported location may not be exactly where you
+would expect.  See more information under <a class="reference internal" href="#parseexception">ParseException</a> .</p>
+</li>
+<li><p class="first">Use the <tt class="docutils literal"><span class="pre">Group</span></tt> class to enclose logical groups of tokens within a
+sublist.  This will help organize your results into more
+hierarchical form (the default behavior is to return matching
+tokens as a flat list of matching input strings).</p>
+</li>
+<li><p class="first">Punctuation may be significant for matching, but is rarely of
+much interest in the parsed results.  Use the <tt class="docutils literal"><span class="pre">suppress()</span></tt> method
+to keep these tokens from cluttering up your returned lists of
+tokens.  For example, <tt class="docutils literal"><span class="pre">delimitedList()</span></tt> matches a succession of
+one or more expressions, separated by delimiters (commas by
+default), but only returns a list of the actual expressions -
+the delimiters are used for parsing, but are suppressed from the
+returned output.</p>
+</li>
+<li><p class="first">Parse actions can be used to convert values from strings to
+other data types (ints, floats, booleans, etc.).</p>
+</li>
+<li><p class="first">Results names are recommended for retrieving tokens from complex
+expressions.  It is much easier to access a token using its field
+name than using a positional index, especially if the expression
+contains optional elements.  You can also shortcut
+the <tt class="docutils literal"><span class="pre">setResultsName</span></tt> call:</p>
+<pre class="literal-block">
+stats = &quot;AVE:&quot; + realNum.setResultsName(&quot;average&quot;) + \
+        &quot;MIN:&quot; + realNum.setResultsName(&quot;min&quot;) + \
+        &quot;MAX:&quot; + realNum.setResultsName(&quot;max&quot;)
+</pre>
+<p>can now be written as this:</p>
+<pre class="literal-block">
+stats = &quot;AVE:&quot; + realNum(&quot;average&quot;) + \
+        &quot;MIN:&quot; + realNum(&quot;min&quot;) + \
+        &quot;MAX:&quot; + realNum(&quot;max&quot;)
+</pre>
+</li>
+<li><p class="first">Be careful when defining parse actions that modify global variables or
+data structures (as in <tt class="docutils literal"><span class="pre">fourFn.py</span></tt>), especially for low level tokens
+or expressions that may occur within an <tt class="docutils literal"><span class="pre">And</span></tt> expression; an early element
+of an <tt class="docutils literal"><span class="pre">And</span></tt> may match, but the overall expression may fail.</p>
+</li>
+<li><p class="first">Performance of pyparsing may be slow for complex grammars and/or large
+input strings.  The <a class="reference external" href="http://psyco.sourceforge.net/">psyco</a> package can be used to improve the speed of the
+pyparsing module with no changes to grammar or program logic - observed
+improvments have been in the 20-50% range.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="classes">
+<h1><a class="toc-backref" href="#id6">2&nbsp;&nbsp;&nbsp;Classes</a></h1>
+<div class="section" id="classes-in-the-pyparsing-module">
+<h2><a class="toc-backref" href="#id7">2.1&nbsp;&nbsp;&nbsp;Classes in the pyparsing module</a></h2>
+<p><tt class="docutils literal"><span class="pre">ParserElement</span></tt> - abstract base class for all pyparsing classes;
+methods for code to use are:</p>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">parseString(</span> <span class="pre">sourceString,</span> <span class="pre">parseAll=False</span> <span class="pre">)</span></tt> - only called once, on the overall
+matching pattern; returns a <a class="reference internal" href="#parseresults">ParseResults</a> object that makes the
+matched tokens available as a list, and optionally as a dictionary,
+or as an object with named attributes; if parseAll is set to True, then
+parseString will raise a ParseException if the grammar does not process
+the complete input string.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">parseFile(</span> <span class="pre">sourceFile</span> <span class="pre">)</span></tt> - a convenience function, that accepts an
+input file object or filename.  The file contents are passed as a
+string to <tt class="docutils literal"><span class="pre">parseString()</span></tt>.  <tt class="docutils literal"><span class="pre">parseFile</span></tt> also supports the <tt class="docutils literal"><span class="pre">parseAll</span></tt> argument.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">scanString(</span> <span class="pre">sourceString</span> <span class="pre">)</span></tt> - generator function, used to find and
+extract matching text in the given source string; for each matched text,
+returns a tuple of:</p>
+<ul class="simple">
+<li>matched tokens (packaged as a <a class="reference internal" href="#parseresults">ParseResults</a> object)</li>
+<li>start location of the matched text in the given source string</li>
+<li>end location in the given source string</li>
+</ul>
+<p><tt class="docutils literal"><span class="pre">scanString</span></tt> allows you to scan through the input source string for
+random matches, instead of exhaustively defining the grammar for the entire
+source text (as would be required with <tt class="docutils literal"><span class="pre">parseString</span></tt>).</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">transformString(</span> <span class="pre">sourceString</span> <span class="pre">)</span></tt> - convenience wrapper function for
+<tt class="docutils literal"><span class="pre">scanString</span></tt>, to process the input source string, and replace matching
+text with the tokens returned from parse actions defined in the grammar
+(see <a class="reference internal" href="#setparseaction">setParseAction</a>).</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">searchString(</span> <span class="pre">sourceString</span> <span class="pre">)</span></tt> - another convenience wrapper function for
+<tt class="docutils literal"><span class="pre">scanString</span></tt>, returns a list of the matching tokens returned from each
+call to <tt class="docutils literal"><span class="pre">scanString</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setName(</span> <span class="pre">name</span> <span class="pre">)</span></tt> - associate a short descriptive name for this
+element, useful in displaying exceptions and trace information</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setResultsName(</span> <span class="pre">string,</span> <span class="pre">listAllMatches=False</span> <span class="pre">)</span></tt> - name to be given
+to tokens matching
+the element; if multiple tokens within
+a repetition group (such as <tt class="docutils literal"><span class="pre">ZeroOrMore</span></tt> or <tt class="docutils literal"><span class="pre">delimitedList</span></tt>) the
+default is to return only the last matching token - if listAllMatches
+is set to True, then a list of matching tokens is returned. Note:
+<tt class="docutils literal"><span class="pre">setResultsName</span></tt> returns a <em>copy</em> of the element so that a single
+basic element can be referenced multiple times and given
+different names within a complex grammar.</p>
+</li>
+</ul>
+<ul id="setparseaction">
+<li><p class="first"><tt class="docutils literal"><span class="pre">setParseAction(</span> <span class="pre">*fn</span> <span class="pre">)</span></tt> - specify one or more functions to call after successful
+matching of the element; each function is defined as <tt class="docutils literal"><span class="pre">fn(</span> <span class="pre">s,</span>
+<span class="pre">loc,</span> <span class="pre">toks</span> <span class="pre">)</span></tt>, where:</p>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">s</span></tt> is the original parse string</li>
+<li><tt class="docutils literal"><span class="pre">loc</span></tt> is the location in the string where matching started</li>
+<li><tt class="docutils literal"><span class="pre">toks</span></tt> is the list of the matched tokens, packaged as a <a class="reference internal" href="#parseresults">ParseResults</a> object</li>
+</ul>
+<p>Multiple functions can be attached to a ParserElement by specifying multiple
+arguments to setParseAction, or by calling setParseAction multiple times.</p>
+<p>Each parse action function can return a modified <tt class="docutils literal"><span class="pre">toks</span></tt> list, to perform conversion, or
+string modifications.  For brevity, <tt class="docutils literal"><span class="pre">fn</span></tt> may also be a
+lambda - here is an example of using a parse action to convert matched
+integer tokens from strings to integers:</p>
+<pre class="literal-block">
+intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] )
+</pre>
+<p>If <tt class="docutils literal"><span class="pre">fn</span></tt> does not modify the <tt class="docutils literal"><span class="pre">toks</span></tt> list, it does not need to return
+anything at all.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setBreak(</span> <span class="pre">breakFlag=True</span> <span class="pre">)</span></tt> - if breakFlag is True, calls pdb.set_break()
+as this expression is about to be parsed</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">copy()</span></tt> - returns a copy of a ParserElement; can be used to use the same
+parse expression in different places in a grammar, with different parse actions
+attached to each</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">leaveWhitespace()</span></tt> - change default behavior of skipping
+whitespace before starting matching (mostly used internally to the
+pyparsing module, rarely used by client code)</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setWhitespaceChars(</span> <span class="pre">chars</span> <span class="pre">)</span></tt> - define the set of chars to be ignored
+as whitespace before trying to match a specific ParserElement, in place of the
+default set of whitespace (space, tab, newline, and return)</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setDefaultWhitespaceChars(</span> <span class="pre">chars</span> <span class="pre">)</span></tt> - class-level method to override
+the default set of whitespace chars for all subsequently created ParserElements
+(including copies); useful when defining grammars that treat one or more of the
+default whitespace characters as significant (such as a line-sensitive grammar, to
+omit newline from the list of ignorable whitespace)</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">suppress()</span></tt> - convenience function to suppress the output of the
+given element, instead of wrapping it with a Suppress object.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">ignore(</span> <span class="pre">expr</span> <span class="pre">)</span></tt> - function to specify parse expression to be
+ignored while matching defined patterns; can be called
+repeatedly to specify multiple expressions; useful to specify
+patterns of comment syntax, for example</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">setDebug(</span> <span class="pre">dbgFlag=True</span> <span class="pre">)</span></tt> - function to enable/disable tracing output
+when trying to match this element</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">validate()</span></tt> - function to verify that the defined grammar does not
+contain infinitely recursive constructs</p>
+</li>
+</ul>
+<ul class="simple" id="parsewithtabs">
+<li><tt class="docutils literal"><span class="pre">parseWithTabs()</span></tt> - function to override default behavior of converting
+tabs to spaces before parsing the input string; rarely used, except when
+specifying whitespace-significant grammars using the <a class="reference internal" href="#white">White</a> class.</li>
+<li><tt class="docutils literal"><span class="pre">enablePackrat()</span></tt> - a class-level static method to enable a memoizing
+performance enhancement, known as &quot;packrat parsing&quot;.  packrat parsing is
+disabled by default, since it may conflict with some user programs that use
+parse actions.  To activate the packrat feature, your
+program must call the class method ParserElement.enablePackrat().  If
+your program uses psyco to &quot;compile as you go&quot;, you must call
+enablePackrat before calling psyco.full().  If you do not do this,
+Python will crash.  For best results, call enablePackrat() immediately
+after importing pyparsing.</li>
+</ul>
+</div>
+<div class="section" id="basic-parserelement-subclasses">
+<h2><a class="toc-backref" href="#id8">2.2&nbsp;&nbsp;&nbsp;Basic ParserElement subclasses</a></h2>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">Literal</span></tt> - construct with a string to be matched exactly</li>
+<li><tt class="docutils literal"><span class="pre">CaselessLiteral</span></tt> - construct with a string to be matched, but
+without case checking; results are always returned as the
+defining literal, NOT as they are found in the input string</li>
+<li><tt class="docutils literal"><span class="pre">Keyword</span></tt> - similar to Literal, but must be immediately followed by
+whitespace, punctuation, or other non-keyword characters; prevents
+accidental matching of a non-keyword that happens to begin with a
+defined keyword</li>
+<li><tt class="docutils literal"><span class="pre">CaselessKeyword</span></tt> - similar to Keyword, but with caseless matching
+behavior</li>
+</ul>
+<ul id="word">
+<li><p class="first"><tt class="docutils literal"><span class="pre">Word</span></tt> - one or more contiguous characters; construct with a
+string containing the set of allowed initial characters, and an
+optional second string of allowed body characters; for instance,
+a common Word construct is to match a code identifier - in C, a
+valid identifier must start with an alphabetic character or an
+underscore ('_'), followed by a body that can also include numeric
+digits.  That is, <tt class="docutils literal"><span class="pre">a</span></tt>, <tt class="docutils literal"><span class="pre">i</span></tt>, <tt class="docutils literal"><span class="pre">MAX_LENGTH</span></tt>, <tt class="docutils literal"><span class="pre">_a1</span></tt>, <tt class="docutils literal"><span class="pre">b_109_</span></tt>, and
+<tt class="docutils literal"><span class="pre">plan9FromOuterSpace</span></tt>
+are all valid identifiers; <tt class="docutils literal"><span class="pre">9b7z</span></tt>, <tt class="docutils literal"><span class="pre">$a</span></tt>, <tt class="docutils literal"><span class="pre">.section</span></tt>, and <tt class="docutils literal"><span class="pre">0debug</span></tt>
+are not.  To
+define an identifier using a Word, use either of the following:</p>
+<pre class="literal-block">
+- Word( alphas+&quot;_&quot;, alphanums+&quot;_&quot; )
+- Word( srange(&quot;[a-zA-Z_]&quot;), srange(&quot;[a-zA-Z0-9_]&quot;) )
+</pre>
+<p>If only one
+string given, it specifies that the same character set defined
+for the initial character is used for the word body; for instance, to
+define an identifier that can only be composed of capital letters and
+underscores, use:</p>
+<pre class="literal-block">
+- Word( &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ_&quot; )
+- Word( srange(&quot;[A-Z_]&quot;) )
+</pre>
+<p>A Word may
+also be constructed with any of the following optional parameters:</p>
+<ul class="simple">
+<li>min - indicating a minimum length of matching characters</li>
+<li>max - indicating a maximum length of matching characters</li>
+<li>exact - indicating an exact length of matching characters</li>
+</ul>
+<p>If exact is specified, it will override any values for min or max.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">CharsNotIn</span></tt> - similar to <a class="reference internal" href="#word">Word</a>, but matches characters not
+in the given constructor string (accepts only one string for both
+initial and body characters); also supports min, max, and exact
+optional parameters.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Regex</span></tt> - a powerful construct, that accepts a regular expression
+to be matched at the current parse position; accepts an optional
+flags parameter, corresponding to the flags parameter in the re.compile
+method; if the expression includes named sub-fields, they will be
+represented in the returned <a class="reference internal" href="#parseresults">ParseResults</a></p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">QuotedString</span></tt> - supports the definition of custom quoted string
+formats, in addition to pyparsing's built-in dblQuotedString and
+sglQuotedString.  QuotedString allows you to specify the following
+parameters:</p>
+<ul class="simple">
+<li>quoteChar - string of one or more characters defining the quote delimiting string</li>
+<li>escChar - character to escape quotes, typically backslash (default=None)</li>
+<li>escQuote - special quote sequence to escape an embedded quote string (such as SQL's &quot;&quot; to escape an embedded &quot;) (default=None)</li>
+<li>multiline - boolean indicating whether quotes can span multiple lines (default=False)</li>
+<li>unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)</li>
+<li>endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None =&gt; same as quoteChar)</li>
+</ul>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">SkipTo</span></tt> - skips ahead in the input string, accepting any
+characters up to the specified pattern; may be constructed with
+the following optional parameters:</p>
+<ul class="simple">
+<li>include - if set to true, also consumes the match expression
+(default is false)</li>
+<li>ignore - allows the user to specify patterns to not be matched,
+to prevent false matches</li>
+<li>failOn - if a literal string or expression is given for this argument, it defines an expression that
+should cause the <tt class="docutils literal"><span class="pre">SkipTo</span></tt> expression to fail, and not skip over that expression</li>
+</ul>
+</li>
+</ul>
+<ul class="simple" id="white">
+<li><tt class="docutils literal"><span class="pre">White</span></tt> - also similar to <a class="reference internal" href="#word">Word</a>, but matches whitespace
+characters.  Not usually needed, as whitespace is implicitly
+ignored by pyparsing.  However, some grammars are whitespace-sensitive,
+such as those that use leading tabs or spaces to indicating grouping
+or hierarchy.  (If matching on tab characters, be sure to call
+<a class="reference internal" href="#parsewithtabs">parseWithTabs</a> on the top-level parse element.)</li>
+<li><tt class="docutils literal"><span class="pre">Empty</span></tt> - a null expression, requiring no characters - will always
+match; useful for debugging and for specialized grammars</li>
+<li><tt class="docutils literal"><span class="pre">NoMatch</span></tt> - opposite of Empty, will never match; useful for debugging
+and for specialized grammars</li>
+</ul>
+</div>
+<div class="section" id="expression-subclasses">
+<h2><a class="toc-backref" href="#id9">2.3&nbsp;&nbsp;&nbsp;Expression subclasses</a></h2>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">And</span></tt> - construct with a list of ParserElements, all of which must
+match for And to match; can also be created using the '+'
+operator; multiple expressions can be Anded together using the '*'
+operator as in:</p>
+<pre class="literal-block">
+ipAddress = Word(nums) + ('.'+Word(nums))*3
+</pre>
+<p>A tuple can be used as the multiplier, indicating a min/max:</p>
+<pre class="literal-block">
+usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
+</pre>
+<p>A special form of <tt class="docutils literal"><span class="pre">And</span></tt> is created if the '-' operator is used
+instead of the '+' operator.  In the ipAddress example above, if
+no trailing '.' and Word(nums) are found after matching the initial
+Word(nums), then pyparsing will back up in the grammar and try other
+alternatives to ipAddress.  However, if ipAddress is defined as:</p>
+<pre class="literal-block">
+strictIpAddress = Word(nums) - ('.'+Word(nums))*3
+</pre>
+<p>then no backing up is done.  If the first Word(nums) of strictIpAddress
+is matched, then any mismatch after that will raise a ParseSyntaxException,
+which will halt the parsing process immediately.  By careful use of the
+'-' operator, grammars can provide meaningful error messages close to
+the location where the incoming text does not match the specified
+grammar.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Or</span></tt> - construct with a list of ParserElements, any of which must
+match for Or to match; if more than one expression matches, the
+expression that makes the longest match will be used; can also
+be created using the '^' operator</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">MatchFirst</span></tt> - construct with a list of ParserElements, any of
+which must match for MatchFirst to match; matching is done
+left-to-right, taking the first expression that matches; can
+also be created using the '|' operator</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Each</span></tt> - similar to And, in that all of the provided expressions
+must match; however, Each permits matching to be done in any order;
+can also be created using the '&amp;' operator</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Optional</span></tt> - construct with a ParserElement, but this element is
+not required to match; can be constructed with an optional <tt class="docutils literal"><span class="pre">default</span></tt> argument,
+containing a default string or object to be supplied if the given optional
+parse element is not found in the input string; parse action will only
+be called if a match is found, or if a default is specified</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">ZeroOrMore</span></tt> - similar to Optional, but can be repeated</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">OneOrMore</span></tt> - similar to ZeroOrMore, but at least one match must
+be present</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">FollowedBy</span></tt> - a lookahead expression, requires matching of the given
+expressions, but does not advance the parsing position within the input string</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">NotAny</span></tt> - a negative lookahead expression, prevents matching of named
+expressions, does not advance the parsing position within the input string;
+can also be created using the unary '~' operator</p>
+</li>
+</ul>
+</div>
+<div class="section" id="expression-operators">
+<span id="operators"></span><h2><a class="toc-backref" href="#id10">2.4&nbsp;&nbsp;&nbsp;Expression operators</a></h2>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">+</span></tt> - consecutive sequence</li>
+<li><tt class="docutils literal"><span class="pre">|</span></tt> - match first alternative</li>
+<li><tt class="docutils literal"><span class="pre">^</span></tt> - match longest alternative</li>
+<li><tt class="docutils literal"><span class="pre">&amp;</span></tt> - match each alternative, in any order</li>
+<li><tt class="docutils literal"><span class="pre">-</span></tt> - like <tt class="docutils literal"><span class="pre">+</span></tt> but with no backup and retry of alternatives</li>
+<li><tt class="docutils literal"><span class="pre">*</span></tt> - repetition of expression</li>
+<li><tt class="docutils literal"><span class="pre">==</span></tt> - matching expression to string; returns True if the string matches the given expression</li>
+<li><tt class="docutils literal"><span class="pre">&lt;&lt;</span></tt> - expression definition for Forward expressions</li>
+</ul>
+</div>
+<div class="section" id="positional-subclasses">
+<h2><a class="toc-backref" href="#id11">2.5&nbsp;&nbsp;&nbsp;Positional subclasses</a></h2>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">StringStart</span></tt> - matches beginning of the text</li>
+<li><tt class="docutils literal"><span class="pre">StringEnd</span></tt> - matches the end of the text</li>
+<li><tt class="docutils literal"><span class="pre">LineStart</span></tt> - matches beginning of a line (lines delimited by <tt class="docutils literal"><span class="pre">\n</span></tt> characters)</li>
+<li><tt class="docutils literal"><span class="pre">LineEnd</span></tt> - matches the end of a line</li>
+<li><tt class="docutils literal"><span class="pre">WordStart</span></tt> - matches a leading word boundary</li>
+<li><tt class="docutils literal"><span class="pre">WordEnd</span></tt> - matches a trailing word boundary</li>
+</ul>
+</div>
+<div class="section" id="converter-subclasses">
+<h2><a class="toc-backref" href="#id12">2.6&nbsp;&nbsp;&nbsp;Converter subclasses</a></h2>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">Upcase</span></tt> - converts matched tokens to uppercase (deprecated -
+use <tt class="docutils literal"><span class="pre">upcaseTokens</span></tt> parse action instead)</li>
+<li><tt class="docutils literal"><span class="pre">Combine</span></tt> - joins all matched tokens into a single string, using
+specified joinString (default <tt class="docutils literal"><span class="pre">joinString=&quot;&quot;</span></tt>); expects
+all matching tokens to be adjacent, with no intervening
+whitespace (can be overridden by specifying <tt class="docutils literal"><span class="pre">adjacent=False</span></tt> in constructor)</li>
+<li><tt class="docutils literal"><span class="pre">Suppress</span></tt> - clears matched tokens; useful to keep returned
+results from being cluttered with required but uninteresting
+tokens (such as list delimiters)</li>
+</ul>
+</div>
+<div class="section" id="special-subclasses">
+<h2><a class="toc-backref" href="#id13">2.7&nbsp;&nbsp;&nbsp;Special subclasses</a></h2>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">Group</span></tt> - causes the matched tokens to be enclosed in a list;
+useful in repeated elements like <tt class="docutils literal"><span class="pre">ZeroOrMore</span></tt> and <tt class="docutils literal"><span class="pre">OneOrMore</span></tt> to
+break up matched tokens into groups for each repeated pattern</li>
+<li><tt class="docutils literal"><span class="pre">Dict</span></tt> - like <tt class="docutils literal"><span class="pre">Group</span></tt>, but also constructs a dictionary, using the
+[0]'th elements of all enclosed token lists as the keys, and
+each token list as the value</li>
+<li><tt class="docutils literal"><span class="pre">SkipTo</span></tt> - catch-all matching expression that accepts all characters
+up until the given pattern is found to match; useful for specifying
+incomplete grammars</li>
+<li><tt class="docutils literal"><span class="pre">Forward</span></tt> - placeholder token used to define recursive token
+patterns; when defining the actual expression later in the
+program, insert it into the <tt class="docutils literal"><span class="pre">Forward</span></tt> object using the <tt class="docutils literal"><span class="pre">&lt;&lt;</span></tt>
+operator (see <tt class="docutils literal"><span class="pre">fourFn.py</span></tt> for an example).</li>
+</ul>
+</div>
+<div class="section" id="other-classes">
+<h2><a class="toc-backref" href="#id14">2.8&nbsp;&nbsp;&nbsp;Other classes</a></h2>
+<ul id="parseresults">
+<li><p class="first"><tt class="docutils literal"><span class="pre">ParseResults</span></tt> - class used to contain and manage the lists of tokens
+created from parsing the input using the user-defined parse
+expression.  ParseResults can be accessed in a number of ways:</p>
+<ul class="simple">
+<li>as a list<ul>
+<li>total list of elements can be found using len()</li>
+<li>individual elements can be found using [0], [1], [-1], etc.</li>
+<li>elements can be deleted using <tt class="docutils literal"><span class="pre">del</span></tt></li>
+<li>the -1th element can be extracted and removed in a single operation
+using <tt class="docutils literal"><span class="pre">pop()</span></tt>, or any element can be extracted and removed
+using <tt class="docutils literal"><span class="pre">pop(n)</span></tt></li>
+</ul>
+</li>
+<li>as a dictionary<ul>
+<li>if <tt class="docutils literal"><span class="pre">setResultsName()</span></tt> is used to name elements within the
+overall parse expression, then these fields can be referenced
+as dictionary elements or as attributes</li>
+<li>the Dict class generates dictionary entries using the data of the
+input text - in addition to ParseResults listed as <tt class="docutils literal"><span class="pre">[</span> <span class="pre">[</span> <span class="pre">a1,</span> <span class="pre">b1,</span> <span class="pre">c1,</span> <span class="pre">...],</span> <span class="pre">[</span> <span class="pre">a2,</span> <span class="pre">b2,</span> <span class="pre">c2,</span> <span class="pre">...]</span>&nbsp; <span class="pre">]</span></tt>
+it also acts as a dictionary with entries defined as <tt class="docutils literal"><span class="pre">{</span> <span class="pre">a1</span> <span class="pre">:</span> <span class="pre">[</span> <span class="pre">b1,</span> <span class="pre">c1,</span> <span class="pre">...</span> <span class="pre">]</span> <span class="pre">},</span> <span class="pre">{</span> <span class="pre">a2</span> <span class="pre">:</span> <span class="pre">[</span> <span class="pre">b2,</span> <span class="pre">c2,</span> <span class="pre">...</span> <span class="pre">]</span> <span class="pre">}</span></tt>;
+this is especially useful when processing tabular data where the first column contains a key
+value for that line of data</li>
+<li>list elements that are deleted using <tt class="docutils literal"><span class="pre">del</span></tt> will still be accessible by their
+dictionary keys</li>
+<li>supports <tt class="docutils literal"><span class="pre">get()</span></tt>, <tt class="docutils literal"><span class="pre">items()</span></tt> and <tt class="docutils literal"><span class="pre">keys()</span></tt> methods, similar to a dictionary</li>
+<li>a keyed item can be extracted and removed using <tt class="docutils literal"><span class="pre">pop(key)</span></tt>.  Here
+key must be non-numeric (such as a string), in order to use dict
+extraction instead of list extraction.</li>
+<li>new named elements can be added (in a parse action, for instance), using the same
+syntax as adding an item to a dict (<tt class="docutils literal"><span class="pre">parseResults[&quot;X&quot;]=&quot;new</span> <span class="pre">item&quot;</span></tt>); named elements can be removed using <tt class="docutils literal"><span class="pre">del</span> <span class="pre">parseResults[&quot;X&quot;]</span></tt></li>
+</ul>
+</li>
+<li>as a nested list<ul>
+<li>results returned from the Group class are encapsulated within their
+own list structure, so that the tokens can be handled as a hierarchical
+tree</li>
+</ul>
+</li>
+</ul>
+<p>ParseResults can also be converted to an ordinary list of strings
+by calling <tt class="docutils literal"><span class="pre">asList()</span></tt>.  Note that this will strip the results of any
+field names that have been defined for any embedded parse elements.
+(The <tt class="docutils literal"><span class="pre">pprint</span></tt> module is especially good at printing out the nested contents
+given by <tt class="docutils literal"><span class="pre">asList()</span></tt>.)</p>
+<p>Finally, ParseResults can be converted to an XML string by calling <tt class="docutils literal"><span class="pre">asXML()</span></tt>. Where
+possible, results will be tagged using the results names defined for the respective
+ParseExpressions.  <tt class="docutils literal"><span class="pre">asXML()</span></tt> takes two optional arguments:</p>
+<ul class="simple">
+<li>doctagname - for ParseResults that do not have a defined name, this argument
+will wrap the resulting XML in a set of opening and closing tags <tt class="docutils literal"><span class="pre">&lt;doctagname&gt;</span></tt>
+and <tt class="docutils literal"><span class="pre">&lt;/doctagname&gt;</span></tt>.</li>
+<li>namedItemsOnly (default=False) - flag to indicate if the generated XML should
+skip items that do not have defined names.  If a nested group item is named, then all
+embedded items will be included, whether they have names or not.</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="exception-classes-and-troubleshooting">
+<h2><a class="toc-backref" href="#id15">2.9&nbsp;&nbsp;&nbsp;Exception classes and Troubleshooting</a></h2>
+<ul id="parseexception">
+<li><p class="first"><tt class="docutils literal"><span class="pre">ParseException</span></tt> - exception returned when a grammar parse fails;
+ParseExceptions have attributes loc, msg, line, lineno, and column; to view the
+text line and location where the reported ParseException occurs, use:</p>
+<pre class="literal-block">
+except ParseException, err:
+    print err.line
+    print &quot; &quot;*(err.column-1) + &quot;^&quot;
+    print err
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">RecursiveGrammarException</span></tt> - exception returned by <tt class="docutils literal"><span class="pre">validate()</span></tt> if
+the grammar contains a recursive infinite loop, such as:</p>
+<pre class="literal-block">
+badGrammar = Forward()
+goodToken = Literal(&quot;A&quot;)
+badGrammar &lt;&lt; Optional(goodToken) + badGrammar
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">ParseFatalException</span></tt> - exception that parse actions can raise to stop parsing
+immediately.  Should be used when a semantic error is found in the input text, such
+as a mismatched XML tag.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">ParseSyntaxException</span></tt> - subclass of <tt class="docutils literal"><span class="pre">ParseFatalException</span></tt> raised when a
+syntax error is found, based on the use of the '-' operator when defining
+a sequence of expressions in an <tt class="docutils literal"><span class="pre">And</span></tt> expression.</p>
+</li>
+</ul>
+<p>You can also get some insights into the parsing logic using diagnostic parse actions,
+and setDebug(), or test the matching of expression fragments by testing them using
+scanString().</p>
+</div>
+</div>
+<div class="section" id="miscellaneous-attributes-and-methods">
+<h1><a class="toc-backref" href="#id16">3&nbsp;&nbsp;&nbsp;Miscellaneous attributes and methods</a></h1>
+<div class="section" id="helper-methods">
+<h2><a class="toc-backref" href="#id17">3.1&nbsp;&nbsp;&nbsp;Helper methods</a></h2>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">delimitedList(</span> <span class="pre">expr,</span> <span class="pre">delim=',')</span></tt> - convenience function for
+matching one or more occurrences of expr, separated by delim.
+By default, the delimiters are suppressed, so the returned results contain
+only the separate list elements.  Can optionally specify <tt class="docutils literal"><span class="pre">combine=True</span></tt>,
+indicating that the expressions and delimiters should be returned as one
+combined value (useful for scoped variables, such as &quot;a.b.c&quot;, or
+&quot;a::b::c&quot;, or paths such as &quot;a/b/c&quot;).</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">countedArray(</span> <span class="pre">expr</span> <span class="pre">)</span></tt> - convenience function for a pattern where an list of
+instances of the given expression are preceded by an integer giving the count of
+elements in the list.  Returns an expression that parses the leading integer,
+reads exactly that many expressions, and returns the array of expressions in the
+parse results - the leading integer is suppressed from the results (although it
+is easily reconstructed by using len on the returned array).</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">oneOf(</span> <span class="pre">string,</span> <span class="pre">caseless=False</span> <span class="pre">)</span></tt> - convenience function for quickly declaring an
+alternative set of <tt class="docutils literal"><span class="pre">Literal</span></tt> tokens, by splitting the given string on
+whitespace boundaries.  The tokens are sorted so that longer
+matches are attempted first; this ensures that a short token does
+not mask a longer one that starts with the same characters. If <tt class="docutils literal"><span class="pre">caseless=True</span></tt>,
+will create an alternative set of CaselessLiteral tokens.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dictOf(</span> <span class="pre">key,</span> <span class="pre">value</span> <span class="pre">)</span></tt> - convenience function for quickly declaring a
+dictionary pattern of <tt class="docutils literal"><span class="pre">Dict(</span> <span class="pre">ZeroOrMore(</span> <span class="pre">Group(</span> <span class="pre">key</span> <span class="pre">+</span> <span class="pre">value</span> <span class="pre">)</span> <span class="pre">)</span> <span class="pre">)</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">nestedExpr(opener,</span> <span class="pre">closer,</span> <span class="pre">content,</span> <span class="pre">ignoreExpr)</span></tt> - helper method for defining
+nested lists enclosed in opening and closing delimiters (&quot;(&quot; and &quot;)&quot; are the default).</p>
+<ul class="simple">
+<li>opener - opening character for a nested list (default=&quot;(&quot;); can also be a pyparsing expression</li>
+<li>closer - closing character for a nested list (default=&quot;)&quot;); can also be a pyparsing expression</li>
+<li>content - expression for items within the nested lists (default=None)</li>
+<li>ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)</li>
+</ul>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">makeHTMLTags(</span> <span class="pre">tagName</span> <span class="pre">)</span></tt> and <tt class="docutils literal"><span class="pre">makeXMLTags(</span> <span class="pre">tagName</span> <span class="pre">)</span></tt> - convenience
+functions to create definitions of opening and closing tag expressions.  Returns
+a pair of expressions, for the corresponding &lt;tag&gt; and &lt;/tag&gt; strings.  Includes
+support for attributes in the opening tag, such as &lt;tag attr1=&quot;abc&quot;&gt; - attributes
+are returned as keyed tokens in the returned ParseResults.  <tt class="docutils literal"><span class="pre">makeHTMLTags</span></tt> is less
+restrictive than <tt class="docutils literal"><span class="pre">makeXMLTags</span></tt>, especially with respect to case sensitivity.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">operatorPrecedence(baseOperand,</span> <span class="pre">operatorList)</span></tt> - convenience function to define a
+grammar for parsing
+expressions with a hierarchical precedence of operators. To use the operatorPrecedence
+helper:</p>
+<ol class="arabic simple">
+<li>Define the base &quot;atom&quot; operand term of the grammar.
+For this simple grammar, the smallest operand is either
+and integer or a variable.  This will be the first argument
+to the operatorPrecedence method.</li>
+<li>Define a list of tuples for each level of operator
+precendence.  Each tuple is of the form
+<tt class="docutils literal"><span class="pre">(opExpr,</span> <span class="pre">numTerms,</span> <span class="pre">rightLeftAssoc,</span> <span class="pre">parseAction)</span></tt>, where:<ul>
+<li>opExpr is the pyparsing expression for the operator;
+may also be a string, which will be converted to a Literal; if
+None, indicates an empty operator, such as the implied
+multiplication operation between 'm' and 'x' in &quot;y = mx + b&quot;.</li>
+<li>numTerms is the number of terms for this operator (must
+be 1 or 2)</li>
+<li>rightLeftAssoc is the indicator whether the operator is
+right or left associative, using the pyparsing-defined
+constants <tt class="docutils literal"><span class="pre">opAssoc.RIGHT</span></tt> and <tt class="docutils literal"><span class="pre">opAssoc.LEFT</span></tt>.</li>
+<li>parseAction is the parse action to be associated with
+expressions matching this operator expression (the
+parse action tuple member may be omitted)</li>
+</ul>
+</li>
+<li>Call operatorPrecedence passing the operand expression and
+the operator precedence list, and save the returned value
+as the generated pyparsing expression.  You can then use
+this expression to parse input strings, or incorporate it
+into a larger, more complex grammar.</li>
+</ol>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">matchPreviousLiteral</span></tt> and <tt class="docutils literal"><span class="pre">matchPreviousExpr</span></tt> - function to define and
+expression that matches the same content
+as was parsed in a previous parse expression.  For instance:</p>
+<pre class="literal-block">
+first = Word(nums)
+matchExpr = first + &quot;:&quot; + matchPreviousLiteral(first)
+</pre>
+<p>will match &quot;1:1&quot;, but not &quot;1:2&quot;.  Since this matches at the literal
+level, this will also match the leading &quot;1:1&quot; in &quot;1:10&quot;.</p>
+<p>In contrast:</p>
+<pre class="literal-block">
+first = Word(nums)
+matchExpr = first + &quot;:&quot; + matchPreviousExpr(first)
+</pre>
+<p>will <em>not</em> match the leading &quot;1:1&quot; in &quot;1:10&quot;; the expressions are
+evaluated first, and then compared, so &quot;1&quot; is compared with &quot;10&quot;.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">nestedExpr(opener,</span> <span class="pre">closer,</span> <span class="pre">content=None,</span> <span class="pre">ignoreExpr=quotedString)</span></tt> - method for defining nested
+lists enclosed in opening and closing delimiters.</p>
+<ul class="simple">
+<li>opener - opening character for a nested list (default=&quot;(&quot;); can also be a pyparsing expression</li>
+<li>closer - closing character for a nested list (default=&quot;)&quot;); can also be a pyparsing expression</li>
+<li>content - expression for items within the nested lists (default=None)</li>
+<li>ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)</li>
+</ul>
+<p>If an expression is not provided for the content argument, the nested
+expression will capture all whitespace-delimited content between delimiters
+as a list of separate values.</p>
+<p>Use the ignoreExpr argument to define expressions that may contain
+opening or closing characters that should not be treated as opening
+or closing characters for nesting, such as quotedString or a comment
+expression.  Specify multiple expressions using an Or or MatchFirst.
+The default is quotedString, but if no expressions are to be ignored,
+then pass None for this argument.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">indentedBlock(</span> <span class="pre">statementExpr,</span> <span class="pre">indentationStackVar,</span> <span class="pre">indent=True)</span></tt> -
+function to define an indented block of statements, similar to
+indentation-based blocking in Python source code:</p>
+<ul class="simple">
+<li>statementExpr is the expression defining a statement that
+will be found in the indented block; a valid indentedBlock
+must contain at least 1 matching statementExpr</li>
+<li>indentationStackVar is a Python list variable; this variable
+should be common to all <tt class="docutils literal"><span class="pre">indentedBlock</span></tt> expressions defined
+within the same grammar, and should be reinitialized to [1]
+each time the grammar is to be used</li>
+<li>indent is a boolean flag indicating whether the expressions
+within the block must be indented from the current parse
+location; if using indentedBlock to define the left-most
+statements (all starting in column 1), set indent to False</li>
+</ul>
+</li>
+</ul>
+<ul id="originaltextfor">
+<li><p class="first"><tt class="docutils literal"><span class="pre">originalTextFor(</span> <span class="pre">expr</span> <span class="pre">)</span></tt> - helper function to preserve the originally parsed text, regardless of any
+token processing or conversion done by the contained expression.  For instance, the following expression:</p>
+<pre class="literal-block">
+fullName = Word(alphas) + Word(alphas)
+</pre>
+<p>will return the parse of &quot;John Smith&quot; as ['John', 'Smith'].  In some applications, the actual name as it
+was given in the input string is what is desired.  To do this, use <tt class="docutils literal"><span class="pre">originalTextFor</span></tt>:</p>
+<pre class="literal-block">
+fullName = originalTextFor(Word(alphas) + Word(alphas))
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">lineno(</span> <span class="pre">loc,</span> <span class="pre">string</span> <span class="pre">)</span></tt> - function to give the line number of the
+location within the string; the first line is line 1, newlines
+start new rows</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">col(</span> <span class="pre">loc,</span> <span class="pre">string</span> <span class="pre">)</span></tt> - function to give the column number of the
+location within the string; the first column is column 1,
+newlines reset the column number to 1</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">line(</span> <span class="pre">loc,</span> <span class="pre">string</span> <span class="pre">)</span></tt> - function to retrieve the line of text
+representing <tt class="docutils literal"><span class="pre">lineno(</span> <span class="pre">loc,</span> <span class="pre">string</span> <span class="pre">)</span></tt>; useful when printing out diagnostic
+messages for exceptions</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">srange(</span> <span class="pre">rangeSpec</span> <span class="pre">)</span></tt> - function to define a string of characters,
+given a string of the form used by regexp string ranges, such as <tt class="docutils literal"><span class="pre">&quot;[0-9]&quot;</span></tt> for
+all numeric digits, <tt class="docutils literal"><span class="pre">&quot;[A-Z_]&quot;</span></tt> for uppercase characters plus underscore, and
+so on (note that rangeSpec does not include support for generic regular
+expressions, just string range specs)</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">getTokensEndLoc()</span></tt> - function to call from within a parse action to get
+the ending location for the matched tokens</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">traceParseAction(fn)</span></tt> - decorator function to debug parse actions. Lists
+each call, called arguments, and return value or exception</p>
+</li>
+</ul>
+</div>
+<div class="section" id="helper-parse-actions">
+<h2><a class="toc-backref" href="#id18">3.2&nbsp;&nbsp;&nbsp;Helper parse actions</a></h2>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">removeQuotes</span></tt> - removes the first and last characters of a quoted string;
+useful to remove the delimiting quotes from quoted strings</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">replaceWith(replString)</span></tt> - returns a parse action that simply returns the
+replString; useful when using transformString, or converting HTML entities, as in:</p>
+<pre class="literal-block">
+nbsp = Literal(&quot;&amp;nbsp;&quot;).setParseAction( replaceWith(&quot;&lt;BLANK&gt;&quot;) )
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">keepOriginalText</span></tt>- (deprecated, use <a class="reference internal" href="#originaltextfor">originalTextFor</a> instead) restores any internal whitespace or suppressed
+text within the tokens for a matched parse
+expression.  This is especially useful when defining expressions
+for scanString or transformString applications.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">withAttribute(</span> <span class="pre">*args,</span> <span class="pre">**kwargs</span> <span class="pre">)</span></tt> - helper to create a validating parse action to be used with start tags created
+with <tt class="docutils literal"><span class="pre">makeXMLTags</span></tt> or <tt class="docutils literal"><span class="pre">makeHTMLTags</span></tt>. Use <tt class="docutils literal"><span class="pre">withAttribute</span></tt> to qualify a starting tag
+with a required attribute value, to avoid false matches on common tags such as
+<tt class="docutils literal"><span class="pre">&lt;TD&gt;</span></tt> or <tt class="docutils literal"><span class="pre">&lt;DIV&gt;</span></tt>.</p>
+<p><tt class="docutils literal"><span class="pre">withAttribute</span></tt> can be called with:</p>
+<ul class="simple">
+<li>keyword arguments, as in <tt class="docutils literal"><span class="pre">(class=&quot;Customer&quot;,align=&quot;right&quot;)</span></tt>, or</li>
+<li>a list of name-value tuples, as in <tt class="docutils literal"><span class="pre">(</span> <span class="pre">(&quot;ns1:class&quot;,</span> <span class="pre">&quot;Customer&quot;),</span> <span class="pre">(&quot;ns2:align&quot;,&quot;right&quot;)</span> <span class="pre">)</span></tt></li>
+</ul>
+<p>An attribute can be specified to have the special value
+<tt class="docutils literal"><span class="pre">withAttribute.ANY_VALUE</span></tt>, which will match any value - use this to
+ensure that an attribute is present but any attribute value is
+acceptable.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">downcaseTokens</span></tt> - converts all matched tokens to lowercase</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">upcaseTokens</span></tt> - converts all matched tokens to uppercase</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">matchOnlyAtCol(</span> <span class="pre">columnNumber</span> <span class="pre">)</span></tt> - a parse action that verifies that
+an expression was matched at a particular column, raising a
+ParseException if matching at a different column number; useful when parsing
+tabular data</p>
+</li>
+</ul>
+</div>
+<div class="section" id="common-string-and-token-constants">
+<h2><a class="toc-backref" href="#id19">3.3&nbsp;&nbsp;&nbsp;Common string and token constants</a></h2>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">alphas</span></tt> - same as <tt class="docutils literal"><span class="pre">string.letters</span></tt></p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">nums</span></tt> - same as <tt class="docutils literal"><span class="pre">string.digits</span></tt></p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">alphanums</span></tt> - a string containing <tt class="docutils literal"><span class="pre">alphas</span> <span class="pre">+</span> <span class="pre">nums</span></tt></p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">alphas8bit</span></tt> - a string containing alphabetic 8-bit characters:</p>
+<pre class="literal-block">
+ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ
+</pre>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">printables</span></tt> - same as <tt class="docutils literal"><span class="pre">string.printable</span></tt>, minus the space (<tt class="docutils literal"><span class="pre">'</span> <span class="pre">'</span></tt>) character</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">empty</span></tt> - a global <tt class="docutils literal"><span class="pre">Empty()</span></tt>; will always match</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">sglQuotedString</span></tt> - a string of characters enclosed in 's; may
+include whitespace, but not newlines</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dblQuotedString</span></tt> - a string of characters enclosed in &quot;s; may
+include whitespace, but not newlines</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">quotedString</span></tt> - <tt class="docutils literal"><span class="pre">sglQuotedString</span> <span class="pre">|</span> <span class="pre">dblQuotedString</span></tt></p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">cStyleComment</span></tt> - a comment block delimited by <tt class="docutils literal"><span class="pre">'/*'</span></tt> and <tt class="docutils literal"><span class="pre">'*/'</span></tt> sequences; can span
+multiple lines, but does not support nesting of comments</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">htmlComment</span></tt> - a comment block delimited by <tt class="docutils literal"><span class="pre">'&lt;!--'</span></tt> and <tt class="docutils literal"><span class="pre">'--&gt;'</span></tt> sequences; can span
+multiple lines, but does not support nesting of comments</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">commaSeparatedList</span></tt> - similar to <tt class="docutils literal"><span class="pre">delimitedList</span></tt>, except that the
+list expressions can be any text value, or a quoted string; quoted strings can
+safely include commas without incorrectly breaking the string into two tokens</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">restOfLine</span></tt> - all remaining printable characters up to but not including the next
+newline</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</body>
+</html>
diff --git a/HowToUsePyparsing.txt b/HowToUsePyparsing.txt
new file mode 100644
--- /dev/null
+++ b/HowToUsePyparsing.txt
@@ -0,0 +1,1011 @@
+==========================
+Using the pyparsing module
+==========================
+
+:author: Paul McGuire
+:address: ptmcg@users.sourceforge.net
+
+:revision: 1.5.2
+:date: April, 2009
+
+:copyright: Copyright |copy| 2003-2009 Paul McGuire. 
+
+.. |copy| unicode:: 0xA9
+
+:abstract: This document provides how-to instructions for the
+    pyparsing library, an easy-to-use Python module for constructing
+    and executing basic text parsers.  The pyparsing module is useful
+    for evaluating user-definable
+    expressions, processing custom application language commands, or
+    extracting data from formatted reports.
+
+.. sectnum::    :depth: 4
+
+.. contents::   :depth: 4
+
+
+Steps to follow
+===============
+
+To parse an incoming data string, the client code must follow these steps:
+
+1. First define the tokens and patterns to be matched, and assign
+   this to a program variable.  Optional results names or parsing
+   actions can also be defined at this time.
+
+2. Call ``parseString()`` or ``scanString()`` on this variable, passing in 
+   the string to
+   be parsed.  During the matching process, whitespace between
+   tokens is skipped by default (although this can be changed).
+   When token matches occur, any defined parse action methods are
+   called.
+
+3. Process the parsed results, returned as a list of strings.
+   Matching results may also be accessed as named attributes of
+   the returned results, if names are defined in the definition of
+   the token pattern, using ``setResultsName()``.
+
+
+Hello, World!
+-------------
+
+The following complete Python program will parse the greeting "Hello, World!",
+or any other greeting of the form "<salutation>, <addressee>!"::
+
+    from pyparsing import Word, alphas
+    
+    greet = Word( alphas ) + "," + Word( alphas ) + "!"
+    greeting = greet.parseString( "Hello, World!" )
+    print greeting
+    
+The parsed tokens are returned in the following form::
+
+    ['Hello', ',', 'World', '!']
+    
+
+New features in 1.5.2
+---------------------
+There are no new pyparsing features in this release, it is primarily a bug-fixing release.
+This release does include changes to support running pyparsing under IronPython 2.0.1, and
+a pyparsing_py3 module for use with Python 3.
+
+
+New features in 1.5.1
+---------------------
+Some of the significant features added in version 1.5.0 are:
+
+- ``originalTextFor`` helper method, to simplify grammar expressions that need to preserve
+  the original input text; should be used in place of the ``keepOriginalText`` parse action::  
+  
+      fullName = Word(alphas) + Word(alphas)
+      fullName.setParseAction(keepOriginalText)
+  
+  should now be written::
+  
+      fullName = originalTextFor(Word(alphas) + Word(alphas))
+  
+- added parameter ``parseAll`` to ``ParserElement.parseFile`` to
+  match the arguments for ``ParserElement.parseString``
+
+- new argument ``failOn`` for SkipTo expressions, to define literal strings or expressions that 
+  should not be included in the skipped text
+
+
+New features in 1.5.0
+---------------------
+Some of the significant features added in version 1.5.0 are:
+
+- ``indentedBlock`` helper method to define grammars using block indentation for grouping (like Python)
+
+- new parameter ``parseAll`` in ``ParserElement.parseString``
+
+- operator '-' for combining ParserElements; similar to the '+' operator, but raises an immediate
+  ``ParseSyntaxException`` if an expression after the '-' operator fails to match; using '-' can 
+  provide error messages that are more useful for application users to find syntax errors in their
+  input text
+
+
+Usage notes
+-----------
+
+- The pyparsing module can be used to interpret simple command
+  strings or algebraic expressions, or can be used to extract data
+  from text reports with complicated format and structure ("screen
+  or report scraping").  However, it is possible that your defined
+  matching patterns may accept invalid inputs.  Use pyparsing to
+  extract data from strings assumed to be well-formatted.  
+
+- To keep up the readability of your code, use operators_  such as ``+``, ``|``, 
+  ``^``, and ``~`` to combine expressions.  You can also combine
+  string literals with ParseExpressions - they will be
+  automatically converted to Literal objects.  For example::
+  
+    integer  = Word( nums )            # simple unsigned integer
+    variable = Word( alphas, max=1 )   # single letter variable, such as x, z, m, etc.
+    arithOp  = Word( "+-*/", max=1 )   # arithmetic operators
+    equation = variable + "=" + integer + arithOp + integer    # will match "x=2+2", etc.
+
+  In the definition of ``equation``, the string ``"="`` will get added as
+  a ``Literal("=")``, but in a more readable way.
+
+- The pyparsing module's default behavior is to ignore whitespace.  This is the
+  case for 99% of all parsers ever written.  This allows you to write simple, clean,
+  grammars, such as the above ``equation``, without having to clutter it up with
+  extraneous ``ws`` markers.  The ``equation`` grammar will successfully parse all of the
+  following statements::
+    
+    x=2+2
+    x = 2+2
+    a = 10   *   4
+    r= 1234/ 100000
+    
+  Of course, it is quite simple to extend this example to support more elaborate expressions, with
+  nesting with parentheses, floating point numbers, scientific notation, and named constants 
+  (such as ``e`` or ``pi``).  See ``fourFn.py``, included in the examples directory.
+
+- To modify pyparsing's default whitespace skipping, you can use one or
+  more of the following methods:
+  
+  - use the static method ``ParserElement.setDefaultWhitespaceChars``
+    to override the normal set of whitespace chars (' \t\n').  For instance
+    when defining a grammar in which newlines are significant, you should
+    call ``ParserElement.setDefaultWhitespaceChars(' \t')`` to remove 
+    newline from the set of skippable whitespace characters.  Calling
+    this method will affect all pyparsing expressions defined afterward.
+    
+  - call ``leaveWhitespace()`` on individual expressions, to suppress the 
+    skipping of whitespace before trying to match the expression
+    
+  - use ``Combine`` to require that successive expressions must be
+    adjacent in the input string.  For instance, this expression::
+    
+      real = Word(nums) + '.' + Word(nums)
+    
+    will match "3.14159", but will also match "3 . 12".  It will also 
+    return the matched results as ['3', '.', '14159'].  By changing this
+    expression to::
+    
+      real = Combine( Word(nums) + '.' + Word(nums) )
+    
+    it will not match numbers with embedded spaces, and it will return a
+    single concatenated string '3.14159' as the parsed token.
+
+- Repetition of expressions can be indicated using the '*' operator.  An
+  expression may be multiplied by an integer value (to indicate an exact
+  repetition count), or by a tuple containing
+  two integers, or None and an integer, representing min and max repetitions
+  (with None representing no min or no max, depending whether it is the first or
+  second tuple element).  See the following examples, where n is used to 
+  indicate an integer value:
+
+  - ``expr*3`` is equivalent to ``expr + expr + expr``
+  
+  - ``expr*(2,3)`` is equivalent to ``expr + expr + Optional(expr)``
+  
+  - ``expr*(n,None)`` or ``expr*(n,)`` is equivalent
+    to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of expr")
+    
+  - ``expr*(None,n)`` is equivalent to ``expr*(0,n)``
+    (read as "0 to n instances of expr")
+    
+  - ``expr*(None,None)`` is equivalent to ``ZeroOrMore(expr)``
+  
+  - ``expr*(1,None)`` is equivalent to ``OneOrMore(expr)``
+
+  Note that ``expr*(None,n)`` does not raise an exception if
+  more than n exprs exist in the input stream; that is,
+  ``expr*(None,n)`` does not enforce a maximum number of expr
+  occurrences.  If this behavior is desired, then write
+  ``expr*(None,n) + ~expr``.
+  
+- ``MatchFirst`` expressions are matched left-to-right, and the first
+  match found will skip all later expressions within, so be sure
+  to define less-specific patterns after more-specific patterns.
+  If you are not sure which expressions are most specific, use Or
+  expressions (defined using the ``^`` operator) - they will always
+  match the longest expression, although they are more
+  compute-intensive.
+  
+- ``Or`` expressions will evaluate all of the specified subexpressions
+  to determine which is the "best" match, that is, which matches
+  the longest string in the input data.  In case of a tie, the
+  left-most expression in the ``Or`` list will win.
+
+- If parsing the contents of an entire file, pass it to the
+  ``parseFile`` method using::
+    
+    expr.parseFile( sourceFile )
+    
+- ``ParseExceptions`` will report the location where an expected token
+  or expression failed to match.  For example, if we tried to use our
+  "Hello, World!" parser to parse "Hello World!" (leaving out the separating
+  comma), we would get an exception, with the message::
+  
+    pyparsing.ParseException: Expected "," (6), (1,7)
+  
+  In the case of complex
+  expressions, the reported location may not be exactly where you
+  would expect.  See more information under ParseException_ .
+
+- Use the ``Group`` class to enclose logical groups of tokens within a
+  sublist.  This will help organize your results into more
+  hierarchical form (the default behavior is to return matching
+  tokens as a flat list of matching input strings).
+  
+- Punctuation may be significant for matching, but is rarely of
+  much interest in the parsed results.  Use the ``suppress()`` method
+  to keep these tokens from cluttering up your returned lists of
+  tokens.  For example, ``delimitedList()`` matches a succession of
+  one or more expressions, separated by delimiters (commas by
+  default), but only returns a list of the actual expressions -
+  the delimiters are used for parsing, but are suppressed from the
+  returned output.
+  
+- Parse actions can be used to convert values from strings to
+  other data types (ints, floats, booleans, etc.).
+  
+- Results names are recommended for retrieving tokens from complex
+  expressions.  It is much easier to access a token using its field
+  name than using a positional index, especially if the expression 
+  contains optional elements.  You can also shortcut
+  the ``setResultsName`` call::
+  
+    stats = "AVE:" + realNum.setResultsName("average") + \
+            "MIN:" + realNum.setResultsName("min") + \
+            "MAX:" + realNum.setResultsName("max")  
+
+  can now be written as this::
+  
+    stats = "AVE:" + realNum("average") + \
+            "MIN:" + realNum("min") + \
+            "MAX:" + realNum("max")  
+  
+- Be careful when defining parse actions that modify global variables or
+  data structures (as in ``fourFn.py``), especially for low level tokens 
+  or expressions that may occur within an ``And`` expression; an early element 
+  of an ``And`` may match, but the overall expression may fail.
+
+- Performance of pyparsing may be slow for complex grammars and/or large
+  input strings.  The psyco_ package can be used to improve the speed of the
+  pyparsing module with no changes to grammar or program logic - observed
+  improvments have been in the 20-50% range.
+
+.. _psyco: http://psyco.sourceforge.net/
+
+
+Classes
+=======
+
+Classes in the pyparsing module
+-------------------------------
+
+``ParserElement`` - abstract base class for all pyparsing classes;
+methods for code to use are:
+
+- ``parseString( sourceString, parseAll=False )`` - only called once, on the overall
+  matching pattern; returns a ParseResults_ object that makes the
+  matched tokens available as a list, and optionally as a dictionary, 
+  or as an object with named attributes; if parseAll is set to True, then
+  parseString will raise a ParseException if the grammar does not process
+  the complete input string.
+
+- ``parseFile( sourceFile )`` - a convenience function, that accepts an
+  input file object or filename.  The file contents are passed as a 
+  string to ``parseString()``.  ``parseFile`` also supports the ``parseAll`` argument.
+  
+- ``scanString( sourceString )`` - generator function, used to find and
+  extract matching text in the given source string; for each matched text, 
+  returns a tuple of:
+  
+  - matched tokens (packaged as a ParseResults_ object)
+  
+  - start location of the matched text in the given source string
+  
+  - end location in the given source string
+  
+  ``scanString`` allows you to scan through the input source string for
+  random matches, instead of exhaustively defining the grammar for the entire
+  source text (as would be required with ``parseString``).
+
+- ``transformString( sourceString )`` - convenience wrapper function for
+  ``scanString``, to process the input source string, and replace matching
+  text with the tokens returned from parse actions defined in the grammar
+  (see setParseAction_).
+
+- ``searchString( sourceString )`` - another convenience wrapper function for
+  ``scanString``, returns a list of the matching tokens returned from each
+  call to ``scanString``.
+
+- ``setName( name )`` - associate a short descriptive name for this
+  element, useful in displaying exceptions and trace information
+
+- ``setResultsName( string, listAllMatches=False )`` - name to be given 
+  to tokens matching
+  the element; if multiple tokens within
+  a repetition group (such as ``ZeroOrMore`` or ``delimitedList``) the
+  default is to return only the last matching token - if listAllMatches
+  is set to True, then a list of matching tokens is returned. Note: 
+  ``setResultsName`` returns a *copy* of the element so that a single
+  basic element can be referenced multiple times and given
+  different names within a complex grammar.
+
+.. _setParseAction:
+
+- ``setParseAction( *fn )`` - specify one or more functions to call after successful
+  matching of the element; each function is defined as ``fn( s,
+  loc, toks )``, where:
+  
+  - ``s`` is the original parse string
+  
+  - ``loc`` is the location in the string where matching started
+  
+  - ``toks`` is the list of the matched tokens, packaged as a ParseResults_ object
+  
+  Multiple functions can be attached to a ParserElement by specifying multiple
+  arguments to setParseAction, or by calling setParseAction multiple times.
+  
+  Each parse action function can return a modified ``toks`` list, to perform conversion, or
+  string modifications.  For brevity, ``fn`` may also be a
+  lambda - here is an example of using a parse action to convert matched
+  integer tokens from strings to integers::
+  
+    intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] )
+
+  If ``fn`` does not modify the ``toks`` list, it does not need to return
+  anything at all.
+
+- ``setBreak( breakFlag=True )`` - if breakFlag is True, calls pdb.set_break()
+  as this expression is about to be parsed
+
+- ``copy()`` - returns a copy of a ParserElement; can be used to use the same
+  parse expression in different places in a grammar, with different parse actions
+  attached to each
+
+- ``leaveWhitespace()`` - change default behavior of skipping
+  whitespace before starting matching (mostly used internally to the 
+  pyparsing module, rarely used by client code)
+
+- ``setWhitespaceChars( chars )`` - define the set of chars to be ignored
+  as whitespace before trying to match a specific ParserElement, in place of the
+  default set of whitespace (space, tab, newline, and return)
+
+- ``setDefaultWhitespaceChars( chars )`` - class-level method to override
+  the default set of whitespace chars for all subsequently created ParserElements
+  (including copies); useful when defining grammars that treat one or more of the
+  default whitespace characters as significant (such as a line-sensitive grammar, to 
+  omit newline from the list of ignorable whitespace)
+
+- ``suppress()`` - convenience function to suppress the output of the
+  given element, instead of wrapping it with a Suppress object.
+
+- ``ignore( expr )`` - function to specify parse expression to be
+  ignored while matching defined patterns; can be called
+  repeatedly to specify multiple expressions; useful to specify
+  patterns of comment syntax, for example
+
+- ``setDebug( dbgFlag=True )`` - function to enable/disable tracing output 
+  when trying to match this element
+
+- ``validate()`` - function to verify that the defined grammar does not
+  contain infinitely recursive constructs
+  
+.. _parseWithTabs:
+
+- ``parseWithTabs()`` - function to override default behavior of converting
+  tabs to spaces before parsing the input string; rarely used, except when
+  specifying whitespace-significant grammars using the White_ class.
+
+- ``enablePackrat()`` - a class-level static method to enable a memoizing
+  performance enhancement, known as "packrat parsing".  packrat parsing is 
+  disabled by default, since it may conflict with some user programs that use
+  parse actions.  To activate the packrat feature, your
+  program must call the class method ParserElement.enablePackrat().  If
+  your program uses psyco to "compile as you go", you must call 
+  enablePackrat before calling psyco.full().  If you do not do this,
+  Python will crash.  For best results, call enablePackrat() immediately
+  after importing pyparsing.
+
+
+Basic ParserElement subclasses
+------------------------------
+
+- ``Literal`` - construct with a string to be matched exactly
+
+- ``CaselessLiteral`` - construct with a string to be matched, but
+  without case checking; results are always returned as the
+  defining literal, NOT as they are found in the input string
+
+- ``Keyword`` - similar to Literal, but must be immediately followed by
+  whitespace, punctuation, or other non-keyword characters; prevents
+  accidental matching of a non-keyword that happens to begin with a
+  defined keyword
+  
+- ``CaselessKeyword`` - similar to Keyword, but with caseless matching
+  behavior
+  
+.. _Word:
+
+- ``Word`` - one or more contiguous characters; construct with a
+  string containing the set of allowed initial characters, and an
+  optional second string of allowed body characters; for instance,
+  a common Word construct is to match a code identifier - in C, a
+  valid identifier must start with an alphabetic character or an 
+  underscore ('_'), followed by a body that can also include numeric
+  digits.  That is, ``a``, ``i``, ``MAX_LENGTH``, ``_a1``, ``b_109_``, and 
+  ``plan9FromOuterSpace``
+  are all valid identifiers; ``9b7z``, ``$a``, ``.section``, and ``0debug``
+  are not.  To
+  define an identifier using a Word, use either of the following::
+  
+  - Word( alphas+"_", alphanums+"_" )
+  - Word( srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]") )
+  
+  If only one
+  string given, it specifies that the same character set defined
+  for the initial character is used for the word body; for instance, to
+  define an identifier that can only be composed of capital letters and
+  underscores, use::
+  
+  - Word( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" )
+  - Word( srange("[A-Z_]") )
+
+  A Word may
+  also be constructed with any of the following optional parameters:
+  
+  - min - indicating a minimum length of matching characters
+  
+  - max - indicating a maximum length of matching characters
+  
+  - exact - indicating an exact length of matching characters
+
+  If exact is specified, it will override any values for min or max.
+
+- ``CharsNotIn`` - similar to Word_, but matches characters not
+  in the given constructor string (accepts only one string for both
+  initial and body characters); also supports min, max, and exact
+  optional parameters.
+
+- ``Regex`` - a powerful construct, that accepts a regular expression
+  to be matched at the current parse position; accepts an optional
+  flags parameter, corresponding to the flags parameter in the re.compile
+  method; if the expression includes named sub-fields, they will be 
+  represented in the returned ParseResults_
+
+- ``QuotedString`` - supports the definition of custom quoted string
+  formats, in addition to pyparsing's built-in dblQuotedString and
+  sglQuotedString.  QuotedString allows you to specify the following 
+  parameters:
+  
+  - quoteChar - string of one or more characters defining the quote delimiting string
+  
+  - escChar - character to escape quotes, typically backslash (default=None)
+  
+  - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
+  
+  - multiline - boolean indicating whether quotes can span multiple lines (default=False)
+  
+  - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
+  
+  - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
+    
+- ``SkipTo`` - skips ahead in the input string, accepting any
+  characters up to the specified pattern; may be constructed with 
+  the following optional parameters:
+  
+  - include - if set to true, also consumes the match expression
+    (default is false)
+  
+  - ignore - allows the user to specify patterns to not be matched,
+    to prevent false matches
+  
+  - failOn - if a literal string or expression is given for this argument, it defines an expression that
+    should cause the ``SkipTo`` expression to fail, and not skip over that expression
+
+.. _White:
+
+- ``White`` - also similar to Word_, but matches whitespace 
+  characters.  Not usually needed, as whitespace is implicitly
+  ignored by pyparsing.  However, some grammars are whitespace-sensitive,
+  such as those that use leading tabs or spaces to indicating grouping
+  or hierarchy.  (If matching on tab characters, be sure to call 
+  parseWithTabs_ on the top-level parse element.)
+  
+- ``Empty`` - a null expression, requiring no characters - will always
+  match; useful for debugging and for specialized grammars
+  
+- ``NoMatch`` - opposite of Empty, will never match; useful for debugging
+  and for specialized grammars
+
+
+Expression subclasses
+---------------------
+
+- ``And`` - construct with a list of ParserElements, all of which must
+  match for And to match; can also be created using the '+'
+  operator; multiple expressions can be Anded together using the '*'
+  operator as in::
+  
+    ipAddress = Word(nums) + ('.'+Word(nums))*3
+    
+  A tuple can be used as the multiplier, indicating a min/max::
+  
+    usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
+
+  A special form of ``And`` is created if the '-' operator is used 
+  instead of the '+' operator.  In the ipAddress example above, if
+  no trailing '.' and Word(nums) are found after matching the initial
+  Word(nums), then pyparsing will back up in the grammar and try other
+  alternatives to ipAddress.  However, if ipAddress is defined as::
+  
+    strictIpAddress = Word(nums) - ('.'+Word(nums))*3
+    
+  then no backing up is done.  If the first Word(nums) of strictIpAddress
+  is matched, then any mismatch after that will raise a ParseSyntaxException,
+  which will halt the parsing process immediately.  By careful use of the
+  '-' operator, grammars can provide meaningful error messages close to 
+  the location where the incoming text does not match the specified
+  grammar.
+
+- ``Or`` - construct with a list of ParserElements, any of which must
+  match for Or to match; if more than one expression matches, the
+  expression that makes the longest match will be used; can also
+  be created using the '^' operator
+
+- ``MatchFirst`` - construct with a list of ParserElements, any of
+  which must match for MatchFirst to match; matching is done
+  left-to-right, taking the first expression that matches; can
+  also be created using the '|' operator
+
+- ``Each`` - similar to And, in that all of the provided expressions
+  must match; however, Each permits matching to be done in any order;
+  can also be created using the '&' operator
+  
+- ``Optional`` - construct with a ParserElement, but this element is
+  not required to match; can be constructed with an optional ``default`` argument,
+  containing a default string or object to be supplied if the given optional
+  parse element is not found in the input string; parse action will only
+  be called if a match is found, or if a default is specified
+
+- ``ZeroOrMore`` - similar to Optional, but can be repeated
+
+- ``OneOrMore`` - similar to ZeroOrMore, but at least one match must
+  be present
+
+- ``FollowedBy`` - a lookahead expression, requires matching of the given
+  expressions, but does not advance the parsing position within the input string
+
+- ``NotAny`` - a negative lookahead expression, prevents matching of named
+  expressions, does not advance the parsing position within the input string; 
+  can also be created using the unary '~' operator
+
+
+.. _operators:
+
+Expression operators
+--------------------
+
+- ``+`` - consecutive sequence
+
+- ``|`` - match first alternative
+
+- ``^`` - match longest alternative
+
+- ``&`` - match each alternative, in any order
+
+- ``-`` - like ``+`` but with no backup and retry of alternatives
+
+- ``*`` - repetition of expression
+
+- ``==`` - matching expression to string; returns True if the string matches the given expression
+
+- ``<<`` - expression definition for Forward expressions
+
+
+Positional subclasses
+---------------------
+
+- ``StringStart`` - matches beginning of the text
+
+- ``StringEnd`` - matches the end of the text
+
+- ``LineStart`` - matches beginning of a line (lines delimited by ``\n`` characters)
+
+- ``LineEnd`` - matches the end of a line
+
+- ``WordStart`` - matches a leading word boundary
+
+- ``WordEnd`` - matches a trailing word boundary
+
+
+
+Converter subclasses
+--------------------
+
+- ``Upcase`` - converts matched tokens to uppercase (deprecated -
+  use ``upcaseTokens`` parse action instead)
+
+- ``Combine`` - joins all matched tokens into a single string, using
+  specified joinString (default ``joinString=""``); expects
+  all matching tokens to be adjacent, with no intervening
+  whitespace (can be overridden by specifying ``adjacent=False`` in constructor)
+
+- ``Suppress`` - clears matched tokens; useful to keep returned
+  results from being cluttered with required but uninteresting
+  tokens (such as list delimiters)
+
+
+Special subclasses
+------------------
+
+- ``Group`` - causes the matched tokens to be enclosed in a list;
+  useful in repeated elements like ``ZeroOrMore`` and ``OneOrMore`` to
+  break up matched tokens into groups for each repeated pattern
+
+- ``Dict`` - like ``Group``, but also constructs a dictionary, using the
+  [0]'th elements of all enclosed token lists as the keys, and
+  each token list as the value
+
+- ``SkipTo`` - catch-all matching expression that accepts all characters
+  up until the given pattern is found to match; useful for specifying
+  incomplete grammars
+
+- ``Forward`` - placeholder token used to define recursive token
+  patterns; when defining the actual expression later in the
+  program, insert it into the ``Forward`` object using the ``<<``
+  operator (see ``fourFn.py`` for an example).
+
+
+Other classes
+-------------
+.. _ParseResults:
+
+- ``ParseResults`` - class used to contain and manage the lists of tokens
+  created from parsing the input using the user-defined parse 
+  expression.  ParseResults can be accessed in a number of ways:
+
+  - as a list
+  
+    - total list of elements can be found using len()
+    
+    - individual elements can be found using [0], [1], [-1], etc.
+    
+    - elements can be deleted using ``del``
+    
+    - the -1th element can be extracted and removed in a single operation
+      using ``pop()``, or any element can be extracted and removed 
+      using ``pop(n)``
+    
+  - as a dictionary
+  
+    - if ``setResultsName()`` is used to name elements within the 
+      overall parse expression, then these fields can be referenced
+      as dictionary elements or as attributes
+      
+    - the Dict class generates dictionary entries using the data of the
+      input text - in addition to ParseResults listed as ``[ [ a1, b1, c1, ...], [ a2, b2, c2, ...]  ]``
+      it also acts as a dictionary with entries defined as ``{ a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }``; 
+      this is especially useful when processing tabular data where the first column contains a key 
+      value for that line of data
+      
+    - list elements that are deleted using ``del`` will still be accessible by their
+      dictionary keys
+      
+    - supports ``get()``, ``items()`` and ``keys()`` methods, similar to a dictionary
+    
+    - a keyed item can be extracted and removed using ``pop(key)``.  Here
+      key must be non-numeric (such as a string), in order to use dict 
+      extraction instead of list extraction.
+      
+    - new named elements can be added (in a parse action, for instance), using the same
+      syntax as adding an item to a dict (``parseResults["X"]="new item"``); named elements can be removed using ``del parseResults["X"]``
+      
+  - as a nested list
+  
+    - results returned from the Group class are encapsulated within their
+      own list structure, so that the tokens can be handled as a hierarchical
+      tree
+      
+  ParseResults can also be converted to an ordinary list of strings
+  by calling ``asList()``.  Note that this will strip the results of any
+  field names that have been defined for any embedded parse elements.
+  (The ``pprint`` module is especially good at printing out the nested contents
+  given by ``asList()``.)
+  
+  Finally, ParseResults can be converted to an XML string by calling ``asXML()``. Where
+  possible, results will be tagged using the results names defined for the respective
+  ParseExpressions.  ``asXML()`` takes two optional arguments:
+  
+  - doctagname - for ParseResults that do not have a defined name, this argument
+    will wrap the resulting XML in a set of opening and closing tags ``<doctagname>``
+    and ``</doctagname>``.
+
+  - namedItemsOnly (default=False) - flag to indicate if the generated XML should 
+    skip items that do not have defined names.  If a nested group item is named, then all
+    embedded items will be included, whether they have names or not.
+
+
+Exception classes and Troubleshooting
+-------------------------------------
+
+.. _ParseException:
+
+- ``ParseException`` - exception returned when a grammar parse fails;
+  ParseExceptions have attributes loc, msg, line, lineno, and column; to view the 
+  text line and location where the reported ParseException occurs, use::
+  
+    except ParseException, err:
+        print err.line
+        print " "*(err.column-1) + "^"
+        print err
+  
+- ``RecursiveGrammarException`` - exception returned by ``validate()`` if
+  the grammar contains a recursive infinite loop, such as::
+  
+    badGrammar = Forward()
+    goodToken = Literal("A")
+    badGrammar << Optional(goodToken) + badGrammar
+
+- ``ParseFatalException`` - exception that parse actions can raise to stop parsing
+  immediately.  Should be used when a semantic error is found in the input text, such
+  as a mismatched XML tag.
+
+- ``ParseSyntaxException`` - subclass of ``ParseFatalException`` raised when a
+  syntax error is found, based on the use of the '-' operator when defining
+  a sequence of expressions in an ``And`` expression.
+
+You can also get some insights into the parsing logic using diagnostic parse actions,
+and setDebug(), or test the matching of expression fragments by testing them using 
+scanString().
+
+
+Miscellaneous attributes and methods
+====================================
+
+Helper methods
+--------------
+
+- ``delimitedList( expr, delim=',')`` - convenience function for
+  matching one or more occurrences of expr, separated by delim.
+  By default, the delimiters are suppressed, so the returned results contain
+  only the separate list elements.  Can optionally specify ``combine=True``,
+  indicating that the expressions and delimiters should be returned as one
+  combined value (useful for scoped variables, such as "a.b.c", or 
+  "a::b::c", or paths such as "a/b/c").
+
+- ``countedArray( expr )`` - convenience function for a pattern where an list of
+  instances of the given expression are preceded by an integer giving the count of
+  elements in the list.  Returns an expression that parses the leading integer,
+  reads exactly that many expressions, and returns the array of expressions in the
+  parse results - the leading integer is suppressed from the results (although it
+  is easily reconstructed by using len on the returned array).
+
+- ``oneOf( string, caseless=False )`` - convenience function for quickly declaring an
+  alternative set of ``Literal`` tokens, by splitting the given string on 
+  whitespace boundaries.  The tokens are sorted so that longer
+  matches are attempted first; this ensures that a short token does
+  not mask a longer one that starts with the same characters. If ``caseless=True``, 
+  will create an alternative set of CaselessLiteral tokens.
+
+- ``dictOf( key, value )`` - convenience function for quickly declaring a 
+  dictionary pattern of ``Dict( ZeroOrMore( Group( key + value ) ) )``.
+
+- ``makeHTMLTags( tagName )`` and ``makeXMLTags( tagName )`` - convenience
+  functions to create definitions of opening and closing tag expressions.  Returns
+  a pair of expressions, for the corresponding <tag> and </tag> strings.  Includes
+  support for attributes in the opening tag, such as <tag attr1="abc"> - attributes
+  are returned as keyed tokens in the returned ParseResults.  ``makeHTMLTags`` is less
+  restrictive than ``makeXMLTags``, especially with respect to case sensitivity.
+
+- ``operatorPrecedence(baseOperand, operatorList)`` - convenience function to define a 
+  grammar for parsing
+  expressions with a hierarchical precedence of operators. To use the operatorPrecedence 
+  helper:
+  
+  1.  Define the base "atom" operand term of the grammar.
+      For this simple grammar, the smallest operand is either
+      and integer or a variable.  This will be the first argument
+      to the operatorPrecedence method.
+      
+  2.  Define a list of tuples for each level of operator
+      precendence.  Each tuple is of the form
+      ``(opExpr, numTerms, rightLeftAssoc, parseAction)``, where:
+      
+      - opExpr is the pyparsing expression for the operator;
+        may also be a string, which will be converted to a Literal; if
+        None, indicates an empty operator, such as the implied
+        multiplication operation between 'm' and 'x' in "y = mx + b".
+      
+      - numTerms is the number of terms for this operator (must
+        be 1 or 2)
+      
+      - rightLeftAssoc is the indicator whether the operator is
+        right or left associative, using the pyparsing-defined
+        constants ``opAssoc.RIGHT`` and ``opAssoc.LEFT``.
+      
+      - parseAction is the parse action to be associated with 
+        expressions matching this operator expression (the
+        parse action tuple member may be omitted)
+        
+  3.  Call operatorPrecedence passing the operand expression and
+      the operator precedence list, and save the returned value
+      as the generated pyparsing expression.  You can then use
+      this expression to parse input strings, or incorporate it
+      into a larger, more complex grammar.
+ 
+- ``matchPreviousLiteral`` and ``matchPreviousExpr`` - function to define and 
+  expression that matches the same content
+  as was parsed in a previous parse expression.  For instance::
+  
+        first = Word(nums)
+        matchExpr = first + ":" + matchPreviousLiteral(first)
+  
+  will match "1:1", but not "1:2".  Since this matches at the literal
+  level, this will also match the leading "1:1" in "1:10".
+  
+  In contrast::
+  
+        first = Word(nums)
+        matchExpr = first + ":" + matchPreviousExpr(first)
+           
+  will *not* match the leading "1:1" in "1:10"; the expressions are
+  evaluated first, and then compared, so "1" is compared with "10".
+
+- ``nestedExpr(opener, closer, content=None, ignoreExpr=quotedString)`` - method for defining nested 
+  lists enclosed in opening and closing delimiters.
+
+  - opener - opening character for a nested list (default="("); can also be a pyparsing expression
+    
+  - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
+    
+  - content - expression for items within the nested lists (default=None)
+    
+  - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
+
+  If an expression is not provided for the content argument, the nested
+  expression will capture all whitespace-delimited content between delimiters
+  as a list of separate values.
+
+  Use the ignoreExpr argument to define expressions that may contain
+  opening or closing characters that should not be treated as opening
+  or closing characters for nesting, such as quotedString or a comment
+  expression.  Specify multiple expressions using an Or or MatchFirst.
+  The default is quotedString, but if no expressions are to be ignored,
+  then pass None for this argument.
+
+
+- ``indentedBlock( statementExpr, indentationStackVar, indent=True)`` -
+  function to define an indented block of statements, similar to 
+  indentation-based blocking in Python source code:
+  
+  - statementExpr is the expression defining a statement that
+    will be found in the indented block; a valid indentedBlock
+    must contain at least 1 matching statementExpr
+       
+  - indentationStackVar is a Python list variable; this variable
+    should be common to all ``indentedBlock`` expressions defined
+    within the same grammar, and should be reinitialized to [1]
+    each time the grammar is to be used
+        
+  - indent is a boolean flag indicating whether the expressions
+    within the block must be indented from the current parse
+    location; if using indentedBlock to define the left-most
+    statements (all starting in column 1), set indent to False
+
+.. _originalTextFor:
+
+- ``originalTextFor( expr )`` - helper function to preserve the originally parsed text, regardless of any
+  token processing or conversion done by the contained expression.  For instance, the following expression::
+  
+        fullName = Word(alphas) + Word(alphas)
+
+  will return the parse of "John Smith" as ['John', 'Smith'].  In some applications, the actual name as it
+  was given in the input string is what is desired.  To do this, use ``originalTextFor``::
+  
+        fullName = originalTextFor(Word(alphas) + Word(alphas))
+
+- ``lineno( loc, string )`` - function to give the line number of the
+  location within the string; the first line is line 1, newlines
+  start new rows
+
+- ``col( loc, string )`` - function to give the column number of the
+  location within the string; the first column is column 1,
+  newlines reset the column number to 1
+
+- ``line( loc, string )`` - function to retrieve the line of text
+  representing ``lineno( loc, string )``; useful when printing out diagnostic
+  messages for exceptions
+
+- ``srange( rangeSpec )`` - function to define a string of characters, 
+  given a string of the form used by regexp string ranges, such as ``"[0-9]"`` for 
+  all numeric digits, ``"[A-Z_]"`` for uppercase characters plus underscore, and 
+  so on (note that rangeSpec does not include support for generic regular 
+  expressions, just string range specs)
+
+- ``getTokensEndLoc()`` - function to call from within a parse action to get
+  the ending location for the matched tokens
+  
+- ``traceParseAction(fn)`` - decorator function to debug parse actions. Lists
+  each call, called arguments, and return value or exception
+  
+  
+
+Helper parse actions
+--------------------
+
+- ``removeQuotes`` - removes the first and last characters of a quoted string;
+  useful to remove the delimiting quotes from quoted strings
+  
+- ``replaceWith(replString)`` - returns a parse action that simply returns the
+  replString; useful when using transformString, or converting HTML entities, as in::
+  
+      nbsp = Literal("&nbsp;").setParseAction( replaceWith("<BLANK>") )
+
+- ``keepOriginalText``- (deprecated, use originalTextFor_ instead) restores any internal whitespace or suppressed 
+  text within the tokens for a matched parse
+  expression.  This is especially useful when defining expressions
+  for scanString or transformString applications.
+
+- ``withAttribute( *args, **kwargs )`` - helper to create a validating parse action to be used with start tags created 
+  with ``makeXMLTags`` or ``makeHTMLTags``. Use ``withAttribute`` to qualify a starting tag 
+  with a required attribute value, to avoid false matches on common tags such as 
+  ``<TD>`` or ``<DIV>``.
+  
+  ``withAttribute`` can be called with:
+  
+  - keyword arguments, as in ``(class="Customer",align="right")``, or
+  
+  - a list of name-value tuples, as in ``( ("ns1:class", "Customer"), ("ns2:align","right") )``
+
+  An attribute can be specified to have the special value 
+  ``withAttribute.ANY_VALUE``, which will match any value - use this to 
+  ensure that an attribute is present but any attribute value is
+  acceptable.
+
+- ``downcaseTokens`` - converts all matched tokens to lowercase
+
+- ``upcaseTokens`` - converts all matched tokens to uppercase
+
+- ``matchOnlyAtCol( columnNumber )`` - a parse action that verifies that
+  an expression was matched at a particular column, raising a 
+  ParseException if matching at a different column number; useful when parsing
+  tabular data
+
+
+
+Common string and token constants
+---------------------------------
+
+- ``alphas`` - same as ``string.letters``
+
+- ``nums`` - same as ``string.digits``
+
+- ``alphanums`` - a string containing ``alphas + nums``
+
+- ``alphas8bit`` - a string containing alphabetic 8-bit characters::
+
+    �������������������������������������������������������������
+
+- ``printables`` - same as ``string.printable``, minus the space (``' '``) character
+
+- ``empty`` - a global ``Empty()``; will always match
+
+- ``sglQuotedString`` - a string of characters enclosed in 's; may
+  include whitespace, but not newlines
+
+- ``dblQuotedString`` - a string of characters enclosed in "s; may
+  include whitespace, but not newlines
+
+- ``quotedString`` - ``sglQuotedString | dblQuotedString``
+
+- ``cStyleComment`` - a comment block delimited by ``'/*'`` and ``'*/'`` sequences; can span
+  multiple lines, but does not support nesting of comments
+
+- ``htmlComment`` - a comment block delimited by ``'<!--'`` and ``'-->'`` sequences; can span
+  multiple lines, but does not support nesting of comments
+
+- ``commaSeparatedList`` - similar to ``delimitedList``, except that the
+  list expressions can be any text value, or a quoted string; quoted strings can
+  safely include commas without incorrectly breaking the string into two tokens
+
+- ``restOfLine`` - all remaining printable characters up to but not including the next
+  newline
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,18 @@
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,7 @@
+include pyparsing.py
+include HowToUsePyparsing.html pyparsingClassDiagram.*
+include README CHANGES LICENSE
+include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html
+include htmldoc/*.*
+include docs/*.*
+include robots.txt
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,72 @@
+====================================
+PyParsing -- A Python Parsing Module
+====================================
+
+Introduction
+============
+
+The pyparsing module is an alternative approach to creating and executing 
+simple grammars, vs. the traditional lex/yacc approach, or the use of 
+regular expressions.  The pyparsing module provides a library of classes 
+that client code uses to construct the grammar directly in Python code.
+
+Here is a program to parse "Hello, World!" (or any greeting of the form 
+"<salutation>, <addressee>!"):
+
+    from pyparsing import Word, alphas
+    greet = Word( alphas ) + "," + Word( alphas ) + "!"
+    hello = "Hello, World!"
+    print hello, "->", greet.parseString( hello )
+
+The program outputs the following:
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the 
+self-explanatory class names, and the use of '+', '|' and '^' operator 
+definitions.
+
+The parsed results returned from parseString() can be accessed as a 
+nested list, a dictionary, or an object with named attributes.
+
+The pyparsing module handles some of the problems that are typically 
+vexing when writing text parsers:
+- extra or missing whitespace (the above program will also handle 
+  "Hello,World!", "Hello  ,  World  !", etc.)
+- quoted strings
+- embedded comments
+
+The .zip file includes examples of a simple SQL parser, simple CORBA IDL 
+parser, a config file parser, a chemical formula parser, and a four-
+function algebraic notation parser.  It also includes a simple how-to 
+document, and a UML class diagram of the library's classes.
+
+
+
+Installation
+============
+
+Do the usual:
+
+    python setup.py install
+    
+(pyparsing requires Python 2.3.2 or later.)
+
+
+Documentation
+=============
+
+See:
+
+    HowToUsePyparsing.html
+
+
+License
+=======
+
+    MIT License. See header of pyparsing.py
+
+History
+=======
+
+    See CHANGES file.
diff --git a/parsingClassDiagram.PNG b/parsingClassDiagram.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..310bfe72b61e39fa2295b397d6f6ead69763b2c6
GIT binary patch
literal 31650
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%0D_PhO<F>3I
zC#6iUp!!!gT&W>JUrWb}&uU;KI<A1KT%}imVa!da1EBaEmJeTn;vKCMZc=4GB4e3v
z(*ybf9Oklw0XQztl!T405TTHhWKS2RpQz@C6gIU~DNUYh%1gIhmIT0B-h!~j`cY2Y
z<T}N9ZGrRRy0?OpVO&2(`VLa2Z9uTj*1c8@BV}NrVmah&uSz{`BcJ*`Fob((JK6K5
z$=2i5esv>G;QN<}X!^NYC&R7k3tz)3yFPq37}f}Ro$9;1G+n_GLGr;?Tz*}$EhLHA
zgOWs^msxLgh28>S-=Ac=B~1Zn<1b`>OZCTCqboe@>=L9QQ@}*@xl5hw`L}i^`%_p1
z`ub#$bk3xcb#ITN@0EXu3{N*+-rwJ_8oH`+1gD=8^`0FRwFF{8?!!0n07RIGN(j^y
zck<eoZTuvCnnGY32h7bcgk4<JSFG!vQx|pJU-I74|3He0j%t76#gO3oFxMuY-Lxlm
zmZ^ER3+)o|a}XFczLVJ{H<!zd-kw-EAvHOy!96%^pKP6J<+Qa~+!?s@j8D@@r*Wk^
zip_(@4xXPihaNs61j`7#<@m9~tMu8f^4B}HV<~6Byl#PW1hwX70Fxq>xa&)rQiFXU
zJl!$elHgLx5QNUA&3>Q-zx=H{@6l&lTiO)-q@{&Ntm(az17s$XDw4X`+TnKE*1_=|
za_ec*#erKZJc5#h@F()zWT)MH#o^1*uird~!SF!#lV2F8|Fw%l&sv{(I}9%0Mn3lD
zSxc8jdOOUVY)i8$L}z3gQc}y4&l^~(E+@3L#3L_uqso>Of_j{gTz4CUt+_y-UyZQR
z*Ml1m7t#?8akLWkAa<8^`Qet9lXnAejg8Mz`I2o*$%%$X1;nhZHLyH_NrAyhA72js
zzL9@}9hhIRAV3b`PgCq0ENfdA$nc`@?@^^4Jw{d@d~5kZPY4<s(=R8wKYX`mz}0)a
z@S{QV<+{nH(B{**dTUBbs6aMOgfPx}b709W#w|%g$$B%lFF=<q>zktf*|y)^fo+jO
zVX*M$uIlx=k{PX2QHk!xQ)QznKDLWPYz7Hub{iO+pE7l^o-WHqXH^%P;9dN!hS37J
zbU`sriTB~-p4Hc)J-ix2pLRBl1;jX_(>YD`GVv~p#idThUek+Aa;k13H0=UsAJi(X
zY#7Bi(O^I6syThT!YTOhLAY>XxXJ7M_6_Vq7VA7^l=Hl2BqxT)h*xPCZlvaKA4@P|
zNFkDHwqN4>AFk<bnIaN!(dkE(&>k3=<?zr>;Om5TTJTXr%_rUM7FqqCJ*G1qh;g^K
z^TO(>I(G-sT>ks8WJv7g5wwnT8oN~!4{8h^-s#BxD7f$uac(Ah{87{zosY~$F7u)!
zT^MqA7)+RWHoT2vv)<XGj(5KpQ%{nf`gPT(6D^mQgv=3gmGBO)NUtpvs4#oRL)8|@
z@qx=-WBr28VDYIKJ_{biG<^xrx_Ry#FZ-!f%cr57F*!4O&tdo1QpT9<F5L+%oVNWO
zLo0fzraa)Zsd^<EHfAH^Q&D$8f=%-JW#a<o5mQSAiF?q&lWbW-v+bDq$`J2m^j4<8
zXn3cL%u6**rRtV6yH&@y1JC!5hvCJ)F6h0Qu9d>1EOy!9@}u6iCVr2g^V`S=Tk+d%
ze$>LZ1>du|S#-o0_8`<m6i`(wrn{naYdhRT@XHS!kWU8VcuGkQ$9b`FPZWPKgl2cz
z`<cMhKo+BB6%St@D@hYi+WtL&%8EIoTy6Tjb)?PEswFeE&>2B^r)I~fZM7Zqy+Ns6
zw0s%+u4z8~+tW1CF}?%?9G9wPK-t^qu|=}Ip)^)i!TUpE%A$?sPo-ApAG(pTqQPQe
z=lSYbEx7gKU#TxwX-MM+jtQ(4RBZQxapF>KD3`)~)7~U%Zwa-_zmTdvx8M~a`+I#%
zN_GsPKB`k*5ba^VF>XSN&}3~`*rV?>?Jl6G-^>OB6DFI!*>mhvR{FhaoqiFEAX%j(
zNNwg#?-DxKD~LH^dmCFz{XVEjMtzX1@~sWci*6vlm%=V$HOUt>v&Y|P7;=IP8=gEU
zf4X#Ftx5s|<&>h8Hxo~-6H7#5A*T!qrp++#F0JepJ<0jROdfUpD<Iqv_hOnZPFBNE
zDOM87RSTd4?x|jqUUxEfuwJ&MCAMHjLiLA@4k5U7`{VoYc8L<|Xp?>KCPXormL*TU
zpoX)>|IT3KhvH3|kxx$D%u%VQ{I%GTt9R(d_Qz1+Yvh=Ndy?V#yE<#m8|TlyMl$G3
zyiU|MNYMvJEIcPei^BA!%H}(qhOQFo{%(7UX3-eD%GY!^U5}Lg$vr8aD<HXkT@o*1
zRknnGSr@$HZo_Pss(8okI`Xf=$ZCI;Q^C#=oEHQ}xw+MRr;|)M#Cff(x!SILv*ro#
z80i(lFL)qs#z$K>ei$H%pp0=R6GyqhbV}j$x%(HJPyZFaF1REgDw!%c{$uQL`eb|;
zEUe*S)b%<IGD)&=@yg`bBTxIf@_Js<ugkIcyfZPXU2$_JxDjs9rHdWwtalAsmrh)7
zjTX|l5O~>^bcDV139N7V!1_)`{oAeP>RLo2(wK&Bofu40pSn82j8^3-6?9d<S9PxD
zwmv?3>%`Z4YK-gAXT%z5S}hGmS{JL$Cu&Y?zyKh_R0nclay4VW{VIIv!tI^+akg<{
zgFmcyjar&5N#7?2&Mvm{^6J#8l(sgyk61G7esFoJKl0PTzUhuD4xedDODWBJL~?-S
z7!)`o2$iPv{$+Os(sheC@!=Uq1_QTbio#mh_G;U&BKieyZtgys>^`}=V77xLMCc7h
zj<_jftJIJ{<vz#lDY>Wm5Riq&>z!1}cgt0!NFq5w^Q&CFlVUOI_m53n%{~UuSMvAE
zwNrn1?7v};y9TIlXlMvr5P@?;(kP4rA%-TRz$c;o&E&==rPo6TN?nd%u9xK5-?9Jv
zhgg2jN3%@XYc@sLX)wEHEu5L^PuU+%_}{$yzkL$s+R!XxFT5%A007M{AKHn2tNZ`}
zS1iZ=gy*k6%=JI`{}p$UH|uN%g?`9Y&Mk%5XfOjXG<++6nM$QDF$VqOuK0ggPbiE5
z05DAdXv<^w{jtrTd$mw&0@;(AB|_`~%(vR?D<OV=^bkK2m%<P039bG1?(xG&bpX(R
z_`yF|LWbfUfj)SiX5`*UC1m>wnXSuMQpDaL0MML{?_i`~?O47Lv7IhB+<-DzTMt9F
z%P1WHK=wH-{YaK<Mz)G`E7B&zSswtjYX0&yo~Lf@jA9N>0AA{1OWq5f4<nw}`*;+9
zFJ)H7@-1JzYfF$`_7SDW&u3p541{w-9tbD2_g?`(FSny^&fhkh%OB#Sa(9EWT}a%)
z5C@fRys1y9{325grgn2XSkHcHR=>y_Pmmfi9Xfv>0HB!LQOEhC1geh7M(xfk?|Z-6
zQE*DPpuSG`XW>J30LGr04Flby0Mtt59}N+vV{PLZd0np}`qg*Yz?7JJ$<Yv{ohyD@
zH-c6;UQ<?Fgv`KHPp%%?`q+60I^7h)S^spp1&+y7Y@hER9BqPs5G%BcF(q>sn~QLQ
zv4?oQDbbaDNqF(df(UYaBW1d$wK2$zLY>UMDBuABQ?6v#eFP?>&l<}fGtE2aQPRfk
z4gq)UO+*(xkxx8Q<~m(Ef9lg6f3%#(m-M{5;vWYenSg@kBe{B0qGn=cy4|zR1r@#)
z>$?{;HSg)+mO@9Z0T{|;z#zL#nkO205Nd-H-6|O--u2}QgOZ}a_lk+=;?YNzjh7?S
z1;6jf<12h=1woH8qjOYLuU9hz+I1GmMRndeGrr&fLCmP7G|G0&Ql+8%FdvvY%Jx>T
zaDoW{^#&%>yvh7eDU%fdEWR9r|BJu;uShXxjW8~zY{t0wKmeML{xpA?!DyFW@|onq
z555Ng^aNaD@kAzZ1AykO3a}@wuP5yGhV+)A!VNajHMhz$MYgL|*M${e0H6ij-$H|I
zPNj{}z7LjWs!t_MHtlZgc$5uPmLCnwT0bPj13>e^%w!mb?lbEDqc+;vBNkGg;D7%n
zTxGZA76gEdnR>I-3^$u=Qs)3@9#=4hFvxhJQbWqR8~}njd1k7&6-O=o`AD15Z`TER
zdZ|B&SEII-m;r6!f!PUty@(EuO4$q*%|gK;7}3U|D(lR3765#&NOha{9D{q`${@TT
zp#}mfXH%m7zMxUEFFw|}x#5-%(B*!p)l&9<H91S&oMtlrp)M?*1AtRg1XIyI-1L??
zJ=0LezlyZkKve8v)v<X>40YRTU;?ZrqQ1eH`LB-0332xroT}nZBIEk83+I8XYgkp*
zrcd8oQ)pvd99w8zxLogch&bi<S|EMF;sh6{#a5e=G)R%ctEQ)nXBdojmFbo2y`ObC
zd$ZH&j*ap)8a}0WW$6QLY94Lh*#_^uD|6^7(RDx|Jy&g$?cwv|mZSQw<~G;D&F)_S
zVDLi@biil$r|LAXgm7cKxLZYOMGkieol=+NQ`!}%!4=}CPB%@I3G$wp3a=ztU&jc<
z?noaxGuZj7r>em-JeJaw3xGE+j{%DjkwI$3iK5yv7YwT9CoNMW#l;Ub1&HhgDDKwD
zjyNPtb+ae>>#T~@x4f%td=a5VQ6yT964k}1nz?CZaj}sUh~n@UJKN+i%gQCGUE+Gl
z-f>CD)LNP@HnwRSx6Km1<1-+T_7aV*YSK>4&Pp#7Oh;w4L)`SIzZk+<(_k6q^phAS
zfodkAWnSO4P50@xRQ19|x8WTr%}pp2jAkaol#QPK_;Is;{#lhN@v$y@ZH053>vGCi
zPsBUYCoG0=fq8kl{v+qyA$Q#MS1Za0VRAx9ta&q3+qy>|JBsQWnQM;~LRHX$XKz}b
zNs~M{G!eMm6ur2|Q^&RZ_-v{K$~KS|jv`rGOn#O2DYFJ3N440ZnKoghvNGXd0<9h*
z`KPCsrtOWm_#sSa43BRk8|3M&7vk*|?)<R_Ewa)*U^iPzL%etDFzSA_rgzqBLXaOA
zFv!$ynl3hKabcX3>Y1vk;cWu7QrL`tUjk%)6eiC}VeD<ygUcSt=P!ThxP%j;{L=Ez
zB!5G0wB6t080rYJXpja|-qJU)KN&A!s0BNJ)4try=|8pvS&1A6Ko0vjaY-e292b_c
z@u?59Gr#IA6Jxi&yR=FyoZQ`ByBD-TiPSIW3--2W#4&*%t|iblOWnlgj6Gg}W?*0o
zEy!{Jv}3c*nrrHCg~h`m0Mx(Ss|^JJ00o1;3lR0E@1g(zCE5jJuw>!!v+MxWKj1XU
z)7{Te@4j}~xMW{zYC=7`;)V>1oSrUnFvjIC%Zf>f*GVTJ<X{&B0C0ut8}n}N?tV?i
z9uiR0Y22ycSG>1XYHM10QL7B~WqM<5dWdXmeEop<@9-f2RGRPQ%c)+doh5(TifY$M
z>gAZ+Nm09iZ|c*})^~D3n+wxc^DadSK*4&jT|tI1x1EdN^g!Fl&=UYaZ$Tc%kWlm)
zT15E;0GfpqDy(|rTX^2-yexpBSO7>1`e;LnHw`aKKZ=PiQuI&2a||`tllornPl=%4
z1}3x<p9j_Td^?3b{=M-rZHGA54sY7oq|)anBJ{t#^=R?~=#w&`_9W6-U8}*JRi6aZ
zcEmcXMEZEcdc%l_U90onkvAH+<To-hV9`0Z!{fG5(!jxdr(|Y11ru-g@S(;XBTt`u
z-&!uIQh(ch)(1I{%<i3VNKAh&xb{mA3QA^p2GK0lbDc8nC~gKri+(01lg`v8pB-J%
z#&(v|aMC336~4^yq(S5BO<6ISSADi5*~Cn8Xwd?${KeSc;X$UwM)a_9{#DyC8WW+^
z)^cIQ$IPOEd?+OWF>$AShagLqL15GL&G7zSG9Ci?;r<XXVuU3r`ecP%%Mg!r%Mer5
z4ZLZ_uWUWp>W3E{TpkINY^UeZ(P^H}CAiK8$&nDRYkJ^L5!GyS1vzso*SRi=oat>X
ztZIZ7fB5<`A4&hE0AjhQB|XLFbWkUc%Kkw<h(BeXhKLdmqSX7vKzpVQbB_`HlGxNs
z$Wq3UZMbG3=~Mf0x_E%Tv-4&Tv;ECid$|ayM)-~yrJtD_wP!$M8p(T-&k%A29XN;J
z;Pgs$M|J%2pcK(kkTSw2XL;}3ytmIe;49K?)*O#e!Bk{^>Y08)Dj^>_mypZtsYo5{
z>h3X~&vsMQtXYmWzJ9=kq3N~!`!B+lVx$-cHqRsGq5{@BCa4on@EfohS_*K9I1?-L
zvrCx|xc=C8$zZrWM_q_BX(t9B<ap+MHjng*t>Tx<G7-{oagYuqHkDrgLZUN+IsNp9
zmkEMFyx)kwQs8l3OH-{V^2Oq&N3l`%f(}I_^Ab)FVoAyCST=BqYk+=xb;(0;+M=Or
z@kujb%=`e59dKuvCsB_-q|?`?4#uU)D47O%;Y>L>fb76GcZ~*{<2C|ExSziKc{hPS
zVHtk19F}F9MH1fI2-~BKH~=vAk;NZdW?B16TOqh)Y6C4r?MiqSNB1I)IpLs6vObo3
zCm{eR%?c;9pQZ+l6F;9c5`CkJ>xu|i5V6;4+@kjSWFyuiX*GxRw@v~eaBY7U;OsnU
z#77Y1T$f)rH!)6}W>%XRR#A6zDi@-;QqSv5=AH0v((>D#PB?Qt%tnS+8H#=<ZmxN{
zlYo41T6{k71Tw)`Qdu~p_6Ba<)~?l#XzBSgCnG38=9ef?FBI3smVbZ9d09hiZW6Q3
z0$i_!c{D?V`+CpC?+LH1qsTgk)Wq42e@J=RVs!FEaHe2y{Tu<baUak<lrP(JrQNi|
z_oF}CbP#SfuWvOxOtYYwAD~A=6Y+XeM=>K`Td4%8mt|~bYoqk?e&;A6jv}BavuHuI
z6ugd0Zq4)vvmCua(qRFvU+K9War!^b8aI6^R}SW9GCr?b9MH$TPP`l3L@2Fq>a+EZ
zTs}lhW&7cLCM?jF=JK^|-7J?GJ)mJ+AgNQrKvaw!@X_=f3G6fYdWj{D_&G4<FmgGh
zL!TFGY!EMh&*JBq3tEvxp4w3X4&do`sh}R!%+wOEe;`;QrT$ZhSYR%}DUm429b(sQ
zowfbU_P&~pHn_vrT{Q4r3r1ux+84W?E%p3dn0|p_dQ=j>{%oDXD!Vruj-ag|J@Cml
zBW*Dk;6Vo|L&4vcAD{1&@)Ew7rQOjHhw#hru>ayrdL<jX0-ELB@}WT~(}KN0NeeOa
z%3Bm=F=Jit-ccKM&mmmuqs(lT6Aq-gG*8JjPF*$4cT2V9ZI?w6^D{3oO8!Wyy<%1s
zMXcSDt`zr9Voty^oLxNJ44~=z)!wntLOq8$A2mtkbjEDbhp|O`A*<={yxzRB3)<Sa
zBxKfMWb{i9_`!pfHj{y;HFzHd_l5AvxGfj1E`0el#izsXaj$<43Qi*J3M6}_vm_5U
zlixjy8XE}_R68<6^A27b_fiMIqsk0Ym#hnMCs~pRpQ>(cTAUD&P7b?E3?ELRlB<#j
z$rr0~fcBh~9=49H^ftlu=UQi#)clQ22`UV3C48ikX7TjiCIFzi_LR9do~5kUNT6b@
zHnXEn1EW|-$W(lC0S*zkk&YjP0^l1@TM7~U<~^vfmIXIEZ$&;jZu4&`HVmcTqKeyT
zg8+90dc9s^moXH8LHC(PJ+h=YCjd5usb=TpNVReRG)J55kCq(%(^oz`XuvXmd-KT)
zOeS&F)94(p(7L9j9-=HbwifxmXT)f~3?`Ua`eey6m3fs^bU18u3ndD=g*@u()k5tP
zD3H~~!c+QAgUd;HqD|s06o67&{dMz5)ZUG|En~Z_1ISS#D<iH2vg*Vy25UbUzo$Bx
zI_H8s3qZ4ZT0UARIf1<9Q*tVEjAyfb!G33j?2N$85i~Lg;<`pByW-S`L&}rmWK!Yu
zO)7o%GysccJ^EMz{-gG}G_$e^m<6eAV4>?^AXOu2HUt9D3>6u3v3Crs<2M4-diKB0
zn4UaOsQ?zi3D5Vu`iL0-yG#0ot3`_V3ctuJ#OrYEt3Mf;Mtp$pxQ*)^H@Mw+%|G%D
z@vtQ3AUSDBH%n2lbja-0$IvTL#H8-W`(~Yegm|+s<~^v9oB8PgMrw9Kt1&Wsb(GhU
z1x&fA`?JhrZf$S?FxFRCG(cxY_TvEne2FmYzYL%N1iyjqullR}nL?-)FG6P)C0x8$
z{w1}6FH5pKL>d6?V_CB1@!iMno~ot>4wQ-y=G<ThK!NgrW9WO<^9$TQL>Ds%07LtA
zb5j#)1w~ey9Ej;(TEbBMWaw?3pU(Z4rSTh%(ar!&S#_H=8`0nyFB54zIC8_v_jEdr
zFXly9{dDffnjabNxFu(quzGI*&^dGy7o@i=?^7~jJhw7X?irz61J75tCfu1`e;WXF
zjl8J~@`F$Rj6lV2JLnT!{S9sawCmFH(GjCb`kfWgWe$>S=dM5jFfK{$5ABeDNGLIS
zt4vW=5Wbj8JojIwUTk<t=NNK8&@4V}#>HPLHONXVtT4<{6uJIt&L(O#QD)%TIRJc%
z|LONVhH5g{61&+}&A5LlhekdE&}^5Mk2Va=x9Up{EdxMX!pf=`LDS^?lr@!SCka5`
z(`r-FXe_DlAD54f;P$1oDXV`79^LR}VTbw__n$MTVkyvlJ`2~ymX#`Nc?@AZ_UA}}
zT?Y$KY1VTH0E-G%A4--P44v#7F*X+uy~j|0PW{x6W)h?FaUH|b9j1fGp}LJ60HCWC
zOd)F08pZ0!AzJo|%CM?W&_pEd$O{bXq#R2bp$*euX2-lw1XX3s#V9;X_uVsA;$_`X
z<(|gg%^nM7>RaXjfDGb3J%!clo%)L9n}GljV%TlgOe>T-(eWGr;38E#@O`w#ccnni
zj8p<Zvw!U!oSYIvdF-)@<t2o0FH(P=>sSJTi8mdlP`hNFa)bqdk$w%~gexP|5A6=R
zGpde5{`DNQf&ZOx2M@6Vu=dT4#q;~|#{HW}z6PJe>)|f$Z(!UqeB1Gse*1e=3}>Ki
z@akc^FPD^c05Hxcn6cNtCDI1&7MT`ugQA~}f5fS@>_SQPO{b;Ltx@Al?DcQ|=q^QY
zE+FZyX5NGOS&CrztF=ju&7MD1bCL^y#b46z(O$o1PGY8&?CN*`KwtVtB>BB}JpP0j
zZ1Vb2V7T7$%2twpJGVx>nr)zVL<K&XHDEymqt*Kr?f}GtIe_e-0gGq3u;ThgdnC#w
z_4kP0;MfxJ*J#bH#$xrHx5HYIdujCwd8M+-l02gn+!c7d2Fh~ejr|eOY(>fIn11LW
zdE5{>UEA#(b>*nqO8n>P_ZC8>Lz0WX+Ax@MQQ&)wlGpJD-Z)%-qt|fuhL0Rqhy~$>
z(y*n!fuYQf1CiPRF*uo8v$obd)3Mb?VPgXG?^8L3avPxThG)c!>fNo5#>-0!X2RQg
zu1xtFASt!Ox@V#x%qJHTW|TR8`kJft4|0JVJ^jK}E~tMfmQ+IgHl|CUrM~FR74^Je
zr-?Xli}<-JBoq~H2<Es2MAT=_4c~|$#<u@>einkhVk-+j(U^>kR3>lV7r|hyJhosm
zo2E^uH|E{6joU^cn)t(t=h+OihEQ(82jIokAF6--Fu?)s@B4!8jXK-ln#p+1J2r*?
z)(Md+*tE}kPD0kGi5Z`8v~&6Dwyb}JGnyzNVHG?nO}AtL7H;KG-l+qm^8T8e5U=G8
zXEk~zSr&p8t8B0`&TF}%gXX&+2{%O<h;U-m*j5WynNMc-z9jRGpRZv8zVDN7V3*I<
zKW??DsjVQVAnoaSE>6_x#*3D`?;HJY9Rn(l|5aqRdkqcp+&-JA>*D$IqwqiiOHZy9
z4{-g0dDo$PQgYjWoB7K<wZB9G(Ei54Q%V>LGHSy3ZnQ7h!w<3oFr}*CZ|@?q_vrA(
zevL1$dbi#msTV=SGqvd?)#2v%T|H3Byg5GB41+DiWbT+b8!ox;ydVf;h_@6t_nGH@
zkQDYYUn$Vq=({Q|4F!O!M;}Wcu9qUO<`L7+_Hswg+Cl(&@P`S@{B1d9nt)AB0viBR
zGl~^f#y!qLnGZIfmgqb*#v}pItdGBgLxw%q=dB~d?zDgPJ1XgaCiU#6R)~0=CaUo`
z08`=r<k(-#WWP0_!gn@iYqa(i%oN^Ddy;}?A!vqm!}rs=?<))V9K`M>rO^eT882Y>
z@4iQC#H<_wMX&!Q@BH6jZIj?&CB^k`jgLfJFCm_cA#Z4Ojt8K2Mu{S*gv^b#wd%Do
z-(Ucg-$8lrL~9Ca?k=rsS`SF*bW{~X!2aWz6pYU@f!gP0?27|Ct3Er~%RPQP9^N11
z`21pacG_x54!r}(5a1ilv{1<G+M*(HXq1qt=pLW3@{P?b*cJ-n5@Gi(4DTLc#GNT0
zrg?EZ-!C1@q186xO6Ost6L*T<RC&e6{%S)(nF?nl25;3VhLmwe8rcifoq3l{nmaZU
zA^_0x8gv_%97nJAzbac-h1=N-ya!-{_~cI1#>Dc?nCT}T)|`WaYlwU}GeA$U_+!Pq
z(A69EoFFGBk7LOBn(Hf*%KBfww&RO7<(@^moc6e$?t%DrYo`c~yw;&>syKJs0v3>5
zm$-^(=-<h044L6j^Y<CsV6C?;NcOl$x+y@3V;EoFLzI7>b4J81s?pv+fkHtl$Iw#Z
z6M80w+WMX1q2Ac7_ZMcA;9wRXJ`~??Jdoh!hd^#ecZ}L}`cz0*s($H^xamKWNIg4Q
zvZah8N15>xl8iYKY2l1yZvM5iT2xYn7z48dd(R3+0{0aOyN2k<=N;WLQd!usL!+9{
zGIT3qwF26_<+$u04q?Y4yVpZE%an0#qM1<8OzP3c>J&Yu2Q5nWNyjA|yVlJqWBiik
z;zhi$PkXR4HBW7%-ZyxXTi%dgGif3epzY*&N>yWa@6<3tORX>8z(-c~eU<*6sFPha
zG-9|sT5q&b@WS_%TKI7YpuNfK5AE<)bHg*5kq4!NevIXkjx5Y1#Xhg=^rq(kkmJDD
zW&Q}!oXFWVZ+BYNGT!A|2&v!|{TiCg7&K~(o1-N<-4^u4O9siM3{}|%4*YV|53~JH
z^RzHoV2D>v9DtIXFm>UW%F+G)ZoKQ}`SIL(`elUO{Z>WwgxU4~E*L5!v)gv|;Hp0(
zJN-2)|D2m%QwS#unM-wK<EL_6WzyK*uck;Spy?LWv*ab}>=kXNXndX6UX;JL<Rb#m
z9=h1z(?11^vvrpH?y-J)<M`<2#R=gBU0S$6-Y}t{Q!&_{FEmxzZV0cU1ki63_neQQ
zOP9u0N3~Fc&olb67HkAYkxgGx*1u7{wel1sUU?dK5ZvL+KkC}AqSl%el_fc7b8os7
zvA&oja0Q8SXnr~iLCZH-6bSC6V8b&aHsb55-pvoSwlSFe{ZC;uXxFA6br`=L&f6K!
zwhb_s0igZfD>KXY=d8nh9dR!%%`ZI}jUxFa*o|$-k&LrGef_xFWe30^<VSan<R32G
zC=1imtS_;9u|soO&(G|hS<V&!zHgHT(3vuAx9wQUmMH~<t*4mHE+X$;F3IDns-mia
zmi&v`=*`6rj^x*4GJ>-?n+=;xZf$BzRjjKG$Ky**l(HLxDT8jaW@+A{q+~D2FFbGT
zs$`uu+CR2J2JJr)Zg#Hw57?ZmeKlsH5v#v3Z9zLf8EIo@gP;ys9OMU6Hz|1?)IvqE
zO!}E05xjQ=BSQ=aR&eg`!W|7ya%Zp<*U^0pXzEH}>PcoYtk)*qF?pnum+x+U?(fQ0
zP8J6|_jc)C%K~)r8E6(w%SYR~l!&|=u}ZlBZwh@-Eq&axvLNKAb1**>Sai3tDi+Tv
zRp@ct#Zz0J#Rf~^tb!40h06dmOVr)L$!%|Z?&!d^ZdG<TOpmY|w8!ZadF5}1e2^LJ
z?3=pO@26&WZeOVVXL#P;4ZPZ^qjr%~O8PjV;-AFePpi!!HfYbD)aBDQB$W)`k@;D{
z0g9HVc}kUET|Z8ne|SSx-4D_KgaV&o0?aqCrlTUeFFgFW1CYnCrDrxdz|>_EmzE><
zO0x5BXnqu|9XPDVh}-4U#xRMg!G%<J+l*PKY+%w{o<pWPFbIfW&M@YMJWl01Zjd!B
zKWV3qyw&{zW5+xAfEB33nXy;8Yu?+a#vi^jd9L;h<mjJ{m#ev_qpbF;^FaH)8GC87
z`e~qjzdsbXr&cn96nQwi!a^VZ^HNJODSkE~;{bfos+0}XM*XuskKDWX+QrrEUq~tS
zj@1v^9;{pA{Q!ao+`h)LKi}*Jy90?=G;343aEl$3CYiDOs@yvYLL6cH%d(IE3_R~6
zui$!02dxCfsX!}B1<l1buwd}Fh=N>XhfChFZJL}o@RiFy>Y63U0(@UF4Wg+NTJau&
zcj`{Z$0PO<)na50s>M(vownzn6a24|*$mQVo2+Qkc&))e+Esu)BZ!5GB<M6P(R;Jm
z0wJZ>PXE=z{od34=wb&|ra%?>4Jn-i1%mB#*nNvQPJ7N{&lHu~N|$B`Z{uU{LC*qT
z)qQK-F*yRz<3d?5t)>X!@%?8^!pm4C(dNz&@XM?j+RZtsui7LakC(sK!QO&x(0c$u
z%LjgPEC#^?f#byWl0u!bcS9|u;=lj)5}G3bynna(StOekABB!s8=65uk*GP;=6V)0
z$U^^nqkZby!QKPxT9Ubpxyks*zQ=5CP_Qm;4lVKSls~;5`oINuMA_~iFLlemVgtUX
z^N)rEVoZka*?Ke~>MOF}&)4{W$3_>ax%vJM-tFxu!`3kYm6zhNV7v1$A4LE|y@o$S
zIk<)o2oEoR(=v2bZ{H0?`w9rt4oziC*FR$xoVo&&$L#q>?P`Ld`+lok=xF*F!eFiT
zgI4l$gGJ_CJv2)lqUrmxENEsg8eqCP*BA46tk@8s^~kXMWTA`WeA2hOyRVQ>a&=iB
zGQ^i01+_QVL)3A?OwHxEIpHRht;SQ7uJqBcn5Fr?AB^_Fgpx=GeUu{Y1qH?iERx!V
z`&vhE4wUzlqfJEUCO=My6)gVB)kEi~G2_*qK|qM#|Kwf&Psr%(X9Dm08&H4R>u+=Q
zat{8>Yz1ge`PZBB;njOC0KkCU|G5qNAN&vg2mgcr!T+Gy|34htgKkKl+Isfu+}Zu+
Oy6!cjtGLT|9{dl)!zCF2

diff --git a/pyparsing.py b/pyparsing.py
new file mode 100644
--- /dev/null
+++ b/pyparsing.py
@@ -0,0 +1,3716 @@
+# module pyparsing.py
+#
+# Copyright (c) 2003-2009  Paul T. McGuire
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+#from __future__ import generators
+
+__doc__ = \
+"""
+pyparsing module - Classes and methods to define and execute parsing grammars
+
+The pyparsing module is an alternative approach to creating and executing simple grammars,
+vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
+don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
+provides a library of classes that you use to construct the grammar directly in Python.
+
+Here is a program to parse "Hello, World!" (or any greeting of the form "<salutation>, <addressee>!")::
+
+    from pyparsing import Word, alphas
+
+    # define grammar of a greeting
+    greet = Word( alphas ) + "," + Word( alphas ) + "!"
+
+    hello = "Hello, World!"
+    print hello, "->", greet.parseString( hello )
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the self-explanatory
+class names, and the use of '+', '|' and '^' operators.
+
+The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an
+object with named attributes.
+
+The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
+ - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
+ - quoted strings
+ - embedded comments
+"""
+
+__version__ = "1.5.2"
+__versionTime__ = "9 April 2009 12:21"
+__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
+
+import string
+from weakref import ref as wkref
+import copy
+import sys
+import warnings
+import re
+import sre_constants
+#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
+
+__all__ = [
+'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
+'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
+'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
+'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
+'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
+'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
+'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
+'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
+'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
+'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums',
+'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
+'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
+'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
+'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
+'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
+'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
+'indentedBlock', 'originalTextFor',
+]
+
+"""
+Detect if we are running version 3.X and make appropriate changes
+Robert A. Clark
+"""
+_PY3K = sys.version_info[0] > 2
+if _PY3K:
+    _MAX_INT = sys.maxsize
+    basestring = str
+    unichr = chr
+    _ustr = str
+    _str2dict = set
+    alphas = string.ascii_lowercase + string.ascii_uppercase
+else:
+    _MAX_INT = sys.maxint
+
+    def _ustr(obj):
+        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
+           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
+           then < returns the unicode object | encodes it with the default encoding | ... >.
+        """
+        if isinstance(obj,unicode):
+            return obj
+
+        try:
+            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
+            # it won't break any existing code.
+            return str(obj)
+
+        except UnicodeEncodeError:
+            # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
+            # state that "The return value must be a string object". However, does a
+            # unicode object (being a subclass of basestring) count as a "string
+            # object"?
+            # If so, then return a unicode object:
+            return unicode(obj)
+            # Else encode it... but how? There are many choices... :)
+            # Replace unprintables with escape codes?
+            #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
+            # Replace unprintables with question marks?
+            #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
+            # ...
+            
+    def _str2dict(strg):
+        return dict( [(c,0) for c in strg] )
+            
+    alphas = string.lowercase + string.uppercase
+
+
+def _xml_escape(data):
+    """Escape &, <, >, ", ', etc. in a string of data."""
+
+    # ampersand must be replaced first
+    from_symbols = '&><"\''
+    to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
+    for from_,to_ in zip(from_symbols, to_symbols):
+        data = data.replace(from_, to_)
+    return data
+
+class _Constants(object):
+    pass
+
+nums       = string.digits
+hexnums    = nums + "ABCDEFabcdef"
+alphanums  = alphas + nums
+_bslash    = chr(92)
+printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
+
+class ParseBaseException(Exception):
+    """base exception class for all parsing runtime exceptions"""
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, pstr, loc=0, msg=None, elem=None ):
+        self.loc = loc
+        if msg is None:
+            self.msg = pstr
+            self.pstr = ""
+        else:
+            self.msg = msg
+            self.pstr = pstr
+        self.parserElement = elem
+
+    def __getattr__( self, aname ):
+        """supported attributes by name are:
+            - lineno - returns the line number of the exception text
+            - col - returns the column number of the exception text
+            - line - returns the line containing the exception text
+        """
+        if( aname == "lineno" ):
+            return lineno( self.loc, self.pstr )
+        elif( aname in ("col", "column") ):
+            return col( self.loc, self.pstr )
+        elif( aname == "line" ):
+            return line( self.loc, self.pstr )
+        else:
+            raise AttributeError(aname)
+
+    def __str__( self ):
+        return "%s (at char %d), (line:%d, col:%d)" % \
+                ( self.msg, self.loc, self.lineno, self.column )
+    def __repr__( self ):
+        return _ustr(self)
+    def markInputline( self, markerString = ">!<" ):
+        """Extracts the exception line from the input string, and marks
+           the location of the exception with a special symbol.
+        """
+        line_str = self.line
+        line_column = self.column - 1
+        if markerString:
+            line_str = "".join( [line_str[:line_column],
+                                markerString, line_str[line_column:]])
+        return line_str.strip()
+    def __dir__(self):
+        return "loc msg pstr parserElement lineno col line " \
+               "markInputLine __str__ __repr__".split()
+
+class ParseException(ParseBaseException):
+    """exception thrown when parse expressions don't match class;
+       supported attributes by name are:
+        - lineno - returns the line number of the exception text
+        - col - returns the column number of the exception text
+        - line - returns the line containing the exception text
+    """
+    pass
+
+class ParseFatalException(ParseBaseException):
+    """user-throwable exception thrown when inconsistent parse content
+       is found; stops all parsing immediately"""
+    pass
+
+class ParseSyntaxException(ParseFatalException):
+    """just like ParseFatalException, but thrown internally when an
+       ErrorStop indicates that parsing is to stop immediately because
+       an unbacktrackable syntax error has been found"""
+    def __init__(self, pe):
+        super(ParseSyntaxException, self).__init__(
+                                    pe.pstr, pe.loc, pe.msg, pe.parserElement)
+
+#~ class ReparseException(ParseBaseException):
+    #~ """Experimental class - parse actions can raise this exception to cause
+       #~ pyparsing to reparse the input string:
+        #~ - with a modified input string, and/or
+        #~ - with a modified start location
+       #~ Set the values of the ReparseException in the constructor, and raise the
+       #~ exception in a parse action to cause pyparsing to use the new string/location.
+       #~ Setting the values as None causes no change to be made.
+       #~ """
+    #~ def __init_( self, newstring, restartLoc ):
+        #~ self.newParseText = newstring
+        #~ self.reparseLoc = restartLoc
+
+class RecursiveGrammarException(Exception):
+    """exception thrown by validate() if the grammar could be improperly recursive"""
+    def __init__( self, parseElementList ):
+        self.parseElementTrace = parseElementList
+
+    def __str__( self ):
+        return "RecursiveGrammarException: %s" % self.parseElementTrace
+
+class _ParseResultsWithOffset(object):
+    def __init__(self,p1,p2):
+        self.tup = (p1,p2)
+    def __getitem__(self,i):
+        return self.tup[i]
+    def __repr__(self):
+        return repr(self.tup)
+    def setOffset(self,i):
+        self.tup = (self.tup[0],i)
+
+class ParseResults(object):
+    """Structured parse results, to provide multiple means of access to the parsed data:
+       - as a list (len(results))
+       - by list index (results[0], results[1], etc.)
+       - by attribute (results.<resultsName>)
+       """
+    __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
+    def __new__(cls, toklist, name=None, asList=True, modal=True ):
+        if isinstance(toklist, cls):
+            return toklist
+        retobj = object.__new__(cls)
+        retobj.__doinit = True
+        return retobj
+
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, toklist, name=None, asList=True, modal=True ):
+        if self.__doinit:
+            self.__doinit = False
+            self.__name = None
+            self.__parent = None
+            self.__accumNames = {}
+            if isinstance(toklist, list):
+                self.__toklist = toklist[:]
+            else:
+                self.__toklist = [toklist]
+            self.__tokdict = dict()
+
+        if name:
+            if not modal:
+                self.__accumNames[name] = 0
+            if isinstance(name,int):
+                name = _ustr(name) # will always return a str, but use _ustr for consistency
+            self.__name = name
+            if not toklist in (None,'',[]):
+                if isinstance(toklist,basestring):
+                    toklist = [ toklist ]
+                if asList:
+                    if isinstance(toklist,ParseResults):
+                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
+                    else:
+                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
+                    self[name].__name = name
+                else:
+                    try:
+                        self[name] = toklist[0]
+                    except (KeyError,TypeError,IndexError):
+                        self[name] = toklist
+
+    def __getitem__( self, i ):
+        if isinstance( i, (int,slice) ):
+            return self.__toklist[i]
+        else:
+            if i not in self.__accumNames:
+                return self.__tokdict[i][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[i] ])
+
+    def __setitem__( self, k, v ):
+        if isinstance(v,_ParseResultsWithOffset):
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
+            sub = v[0]
+        elif isinstance(k,int):
+            self.__toklist[k] = v
+            sub = v
+        else:
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
+            sub = v
+        if isinstance(sub,ParseResults):
+            sub.__parent = wkref(self)
+
+    def __delitem__( self, i ):
+        if isinstance(i,(int,slice)):
+            mylen = len( self.__toklist )
+            del self.__toklist[i]
+
+            # convert int to slice
+            if isinstance(i, int):
+                if i < 0:
+                    i += mylen
+                i = slice(i, i+1)
+            # get removed indices
+            removed = list(range(*i.indices(mylen)))
+            removed.reverse()
+            # fixup indices in token dictionary
+            for name in self.__tokdict:
+                occurrences = self.__tokdict[name]
+                for j in removed:
+                    for k, (value, position) in enumerate(occurrences):
+                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
+        else:
+            del self.__tokdict[i]
+
+    def __contains__( self, k ):
+        return k in self.__tokdict
+
+    def __len__( self ): return len( self.__toklist )
+    def __bool__(self): return len( self.__toklist ) > 0
+    __nonzero__ = __bool__
+    def __iter__( self ): return iter( self.__toklist )
+    def __reversed__( self ): return iter( reversed(self.__toklist) )
+    def keys( self ):
+        """Returns all named result keys."""
+        return self.__tokdict.keys()
+
+    def pop( self, index=-1 ):
+        """Removes and returns item at specified index (default=last).
+           Will work with either numeric indices or dict-key indicies."""
+        ret = self[index]
+        del self[index]
+        return ret
+
+    def get(self, key, defaultValue=None):
+        """Returns named result matching the given key, or if there is no
+           such name, then returns the given defaultValue or None if no
+           defaultValue is specified."""
+        if key in self:
+            return self[key]
+        else:
+            return defaultValue
+
+    def insert( self, index, insStr ):
+        self.__toklist.insert(index, insStr)
+        # fixup indices in token dictionary
+        for name in self.__tokdict:
+            occurrences = self.__tokdict[name]
+            for k, (value, position) in enumerate(occurrences):
+                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
+
+    def items( self ):
+        """Returns all named result keys and values as a list of tuples."""
+        return [(k,self[k]) for k in self.__tokdict]
+
+    def values( self ):
+        """Returns all named result values."""
+        return [ v[-1][0] for v in self.__tokdict.values() ]
+
+    def __getattr__( self, name ):
+        if name not in self.__slots__:
+            if name in self.__tokdict:
+                if name not in self.__accumNames:
+                    return self.__tokdict[name][-1][0]
+                else:
+                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
+            else:
+                return ""
+        return None
+
+    def __add__( self, other ):
+        ret = self.copy()
+        ret += other
+        return ret
+
+    def __iadd__( self, other ):
+        if other.__tokdict:
+            offset = len(self.__toklist)
+            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
+            otheritems = other.__tokdict.items()
+            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
+                                for (k,vlist) in otheritems for v in vlist]
+            for k,v in otherdictitems:
+                self[k] = v
+                if isinstance(v[0],ParseResults):
+                    v[0].__parent = wkref(self)
+            
+        self.__toklist += other.__toklist
+        self.__accumNames.update( other.__accumNames )
+        del other
+        return self
+
+    def __repr__( self ):
+        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
+
+    def __str__( self ):
+        out = "["
+        sep = ""
+        for i in self.__toklist:
+            if isinstance(i, ParseResults):
+                out += sep + _ustr(i)
+            else:
+                out += sep + repr(i)
+            sep = ", "
+        out += "]"
+        return out
+
+    def _asStringList( self, sep='' ):
+        out = []
+        for item in self.__toklist:
+            if out and sep:
+                out.append(sep)
+            if isinstance( item, ParseResults ):
+                out += item._asStringList()
+            else:
+                out.append( _ustr(item) )
+        return out
+
+    def asList( self ):
+        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
+        out = []
+        for res in self.__toklist:
+            if isinstance(res,ParseResults):
+                out.append( res.asList() )
+            else:
+                out.append( res )
+        return out
+
+    def asDict( self ):
+        """Returns the named parse results as dictionary."""
+        return dict( self.items() )
+
+    def copy( self ):
+        """Returns a new copy of a ParseResults object."""
+        ret = ParseResults( self.__toklist )
+        ret.__tokdict = self.__tokdict.copy()
+        ret.__parent = self.__parent
+        ret.__accumNames.update( self.__accumNames )
+        ret.__name = self.__name
+        return ret
+
+    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
+        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
+        nl = "\n"
+        out = []
+        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
+                                                            for v in vlist ] )
+        nextLevelIndent = indent + "  "
+
+        # collapse out indents if formatting is not desired
+        if not formatted:
+            indent = ""
+            nextLevelIndent = ""
+            nl = ""
+
+        selfTag = None
+        if doctag is not None:
+            selfTag = doctag
+        else:
+            if self.__name:
+                selfTag = self.__name
+
+        if not selfTag:
+            if namedItemsOnly:
+                return ""
+            else:
+                selfTag = "ITEM"
+
+        out += [ nl, indent, "<", selfTag, ">" ]
+
+        worklist = self.__toklist
+        for i,res in enumerate(worklist):
+            if isinstance(res,ParseResults):
+                if i in namedItems:
+                    out += [ res.asXML(namedItems[i],
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+                else:
+                    out += [ res.asXML(None,
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+            else:
+                # individual token, see if there is a name for it
+                resTag = None
+                if i in namedItems:
+                    resTag = namedItems[i]
+                if not resTag:
+                    if namedItemsOnly:
+                        continue
+                    else:
+                        resTag = "ITEM"
+                xmlBodyText = _xml_escape(_ustr(res))
+                out += [ nl, nextLevelIndent, "<", resTag, ">",
+                                                xmlBodyText,
+                                                "</", resTag, ">" ]
+
+        out += [ nl, indent, "</", selfTag, ">" ]
+        return "".join(out)
+
+    def __lookup(self,sub):
+        for k,vlist in self.__tokdict.items():
+            for v,loc in vlist:
+                if sub is v:
+                    return k
+        return None
+
+    def getName(self):
+        """Returns the results name for this token expression."""
+        if self.__name:
+            return self.__name
+        elif self.__parent:
+            par = self.__parent()
+            if par:
+                return par.__lookup(self)
+            else:
+                return None
+        elif (len(self) == 1 and
+               len(self.__tokdict) == 1 and
+               self.__tokdict.values()[0][0][1] in (0,-1)):
+            return self.__tokdict.keys()[0]
+        else:
+            return None
+
+    def dump(self,indent='',depth=0):
+        """Diagnostic method for listing out the contents of a ParseResults.
+           Accepts an optional indent argument so that this string can be embedded
+           in a nested display of other data."""
+        out = []
+        out.append( indent+_ustr(self.asList()) )
+        keys = self.items()
+        keys.sort()
+        for k,v in keys:
+            if out:
+                out.append('\n')
+            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
+            if isinstance(v,ParseResults):
+                if v.keys():
+                    out.append( v.dump(indent,depth+1) )
+                else:
+                    out.append(_ustr(v))
+            else:
+                out.append(_ustr(v))
+        return "".join(out)
+
+    # add support for pickle protocol
+    def __getstate__(self):
+        return ( self.__toklist,
+                 ( self.__tokdict.copy(),
+                   self.__parent is not None and self.__parent() or None,
+                   self.__accumNames,
+                   self.__name ) )
+
+    def __setstate__(self,state):
+        self.__toklist = state[0]
+        self.__tokdict, \
+        par, \
+        inAccumNames, \
+        self.__name = state[1]
+        self.__accumNames = {}
+        self.__accumNames.update(inAccumNames)
+        if par is not None:
+            self.__parent = wkref(par)
+        else:
+            self.__parent = None
+
+    def __dir__(self):
+        return dir(super(ParseResults,self)) + self.keys()
+
+def col (loc,strg):
+    """Returns current column within a string, counting newlines as line separators.
+   The first column is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
+   on parsing strings containing <TAB>s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
+
+def lineno(loc,strg):
+    """Returns current line number within a string, counting newlines as line separators.
+   The first line is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
+   on parsing strings containing <TAB>s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return strg.count("\n",0,loc) + 1
+
+def line( loc, strg ):
+    """Returns the line of text containing loc within a string, counting newlines as line separators.
+       """
+    lastCR = strg.rfind("\n", 0, loc)
+    nextCR = strg.find("\n", loc)
+    if nextCR > 0:
+        return strg[lastCR+1:nextCR]
+    else:
+        return strg[lastCR+1:]
+
+def _defaultStartDebugAction( instring, loc, expr ):
+    print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+
+def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
+    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
+
+def _defaultExceptionDebugAction( instring, loc, expr, exc ):
+    print ("Exception raised:" + _ustr(exc))
+
+def nullDebugAction(*args):
+    """'Do-nothing' debug action, to suppress debugging output during parsing."""
+    pass
+
+class ParserElement(object):
+    """Abstract base level parser element class."""
+    DEFAULT_WHITE_CHARS = " \n\t\r"
+
+    def setDefaultWhitespaceChars( chars ):
+        """Overrides the default whitespace chars
+        """
+        ParserElement.DEFAULT_WHITE_CHARS = chars
+    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
+
+    def __init__( self, savelist=False ):
+        self.parseAction = list()
+        self.failAction = None
+        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
+        self.strRepr = None
+        self.resultsName = None
+        self.saveAsList = savelist
+        self.skipWhitespace = True
+        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        self.copyDefaultWhiteChars = True
+        self.mayReturnEmpty = False # used when checking for left-recursion
+        self.keepTabs = False
+        self.ignoreExprs = list()
+        self.debug = False
+        self.streamlined = False
+        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
+        self.errmsg = ""
+        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
+        self.debugActions = ( None, None, None ) #custom debug actions
+        self.re = None
+        self.callPreparse = True # used to avoid redundant calls to preParse
+        self.callDuringTry = False
+
+    def copy( self ):
+        """Make a copy of this ParserElement.  Useful for defining different parse actions
+           for the same parsing pattern, using copies of the original parse element."""
+        cpy = copy.copy( self )
+        cpy.parseAction = self.parseAction[:]
+        cpy.ignoreExprs = self.ignoreExprs[:]
+        if self.copyDefaultWhiteChars:
+            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        return cpy
+
+    def setName( self, name ):
+        """Define name for this expression, for use in debugging."""
+        self.name = name
+        self.errmsg = "Expected " + self.name
+        if hasattr(self,"exception"):
+            self.exception.msg = self.errmsg
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        """Define name for referencing matching tokens as a nested attribute
+           of the returned parse results.
+           NOTE: this returns a *copy* of the original ParserElement object;
+           this is so that the client can define a basic element, such as an
+           integer, and reference it in multiple places with different names.
+        """
+        newself = self.copy()
+        newself.resultsName = name
+        newself.modalResults = not listAllMatches
+        return newself
+
+    def setBreak(self,breakFlag = True):
+        """Method to invoke the Python pdb debugger when this element is
+           about to be parsed. Set breakFlag to True to enable, False to
+           disable.
+        """
+        if breakFlag:
+            _parseMethod = self._parse
+            def breaker(instring, loc, doActions=True, callPreParse=True):
+                import pdb
+                pdb.set_trace()
+                return _parseMethod( instring, loc, doActions, callPreParse )
+            breaker._originalParseMethod = _parseMethod
+            self._parse = breaker
+        else:
+            if hasattr(self._parse,"_originalParseMethod"):
+                self._parse = self._parse._originalParseMethod
+        return self
+
+    def _normalizeParseActionArgs( f ):
+        """Internal method used to decorate parse actions that take fewer than 3 arguments,
+           so that all parse actions can be called as f(s,l,t)."""
+        STAR_ARGS = 4
+
+        try:
+            restore = None
+            if isinstance(f,type):
+                restore = f
+                f = f.__init__
+            if not _PY3K:
+                codeObj = f.func_code
+            else:
+                codeObj = f.code
+            if codeObj.co_flags & STAR_ARGS:
+                return f
+            numargs = codeObj.co_argcount
+            if not _PY3K:
+                if hasattr(f,"im_self"):
+                    numargs -= 1
+            else:
+                if hasattr(f,"__self__"):
+                    numargs -= 1
+            if restore:
+                f = restore
+        except AttributeError:
+            try:
+                if not _PY3K:
+                    call_im_func_code = f.__call__.im_func.func_code
+                else:
+                    call_im_func_code = f.__code__
+
+                # not a function, must be a callable object, get info from the
+                # im_func binding of its bound __call__ method
+                if call_im_func_code.co_flags & STAR_ARGS:
+                    return f
+                numargs = call_im_func_code.co_argcount
+                if not _PY3K:
+                    if hasattr(f.__call__,"im_self"):
+                        numargs -= 1
+                else:
+                    if hasattr(f.__call__,"__self__"):
+                        numargs -= 0
+            except AttributeError:
+                if not _PY3K:
+                    call_func_code = f.__call__.func_code
+                else:
+                    call_func_code = f.__call__.__code__
+                # not a bound method, get info directly from __call__ method
+                if call_func_code.co_flags & STAR_ARGS:
+                    return f
+                numargs = call_func_code.co_argcount
+                if not _PY3K:
+                    if hasattr(f.__call__,"im_self"):
+                        numargs -= 1
+                else:
+                    if hasattr(f.__call__,"__self__"):
+                        numargs -= 1
+
+
+        #~ print ("adding function %s with %d args" % (f.func_name,numargs))
+        if numargs == 3:
+            return f
+        else:
+            if numargs > 3:
+                def tmp(s,l,t):
+                    return f(f.__call__.__self__, s,l,t)
+            if numargs == 2:
+                def tmp(s,l,t):
+                    return f(l,t)
+            elif numargs == 1:
+                def tmp(s,l,t):
+                    return f(t)
+            else: #~ numargs == 0:
+                def tmp(s,l,t):
+                    return f()
+            try:
+                tmp.__name__ = f.__name__
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            try:
+                tmp.__doc__ = f.__doc__
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            try:
+                tmp.__dict__.update(f.__dict__)
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            return tmp
+    _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs)
+
+    def setParseAction( self, *fns, **kwargs ):
+        """Define action to perform when successfully matching parse element definition.
+           Parse action fn is a callable method with 0-3 arguments, called as fn(s,loc,toks),
+           fn(loc,toks), fn(toks), or just fn(), where:
+            - s   = the original string being parsed (see note below)
+            - loc = the location of the matching substring
+            - toks = a list of the matched tokens, packaged as a ParseResults object
+           If the functions in fns modify the tokens, they can return them as the return
+           value from fn, and the modified list of tokens will replace the original.
+           Otherwise, fn does not need to return any value.
+
+           Note: the default parsing behavior is to expand tabs in the input string
+           before starting the parsing process.  See L{I{parseString}<parseString>} for more information
+           on parsing strings containing <TAB>s, and suggested methods to maintain a
+           consistent view of the parsed string, the parse location, and line and column
+           positions within the parsed string.
+           """
+        self.parseAction = list(map(self._normalizeParseActionArgs, list(fns)))
+        self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
+        return self
+
+    def addParseAction( self, *fns, **kwargs ):
+        """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
+        self.parseAction += list(map(self._normalizeParseActionArgs, list(fns)))
+        self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
+        return self
+
+    def setFailAction( self, fn ):
+        """Define action to perform if parsing fails at this expression.
+           Fail acton fn is a callable function that takes the arguments
+           fn(s,loc,expr,err) where:
+            - s = string being parsed
+            - loc = location where expression match was attempted and failed
+            - expr = the parse expression that failed
+            - err = the exception thrown
+           The function returns no value.  It may throw ParseFatalException
+           if it is desired to stop parsing immediately."""
+        self.failAction = fn
+        return self
+
+    def _skipIgnorables( self, instring, loc ):
+        exprsFound = True
+        while exprsFound:
+            exprsFound = False
+            for e in self.ignoreExprs:
+                try:
+                    while 1:
+                        loc,dummy = e._parse( instring, loc )
+                        exprsFound = True
+                except ParseException:
+                    pass
+        return loc
+
+    def preParse( self, instring, loc ):
+        if self.ignoreExprs:
+            loc = self._skipIgnorables( instring, loc )
+
+        if self.skipWhitespace:
+            wt = self.whiteChars
+            instrlen = len(instring)
+            while loc < instrlen and instring[loc] in wt:
+                loc += 1
+
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        return loc, []
+
+    def postParse( self, instring, loc, tokenlist ):
+        return tokenlist
+
+    #~ @profile
+    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
+        debugging = ( self.debug ) #and doActions )
+
+        if debugging or self.failAction:
+            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+            if (self.debugActions[0] ):
+                self.debugActions[0]( instring, loc, self )
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = loc
+            try:
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            except ParseBaseException:
+                #~ print ("Exception raised:", err)
+                err = None
+                if self.debugActions[2]:
+                    err = sys.exc_info()[1]
+                    self.debugActions[2]( instring, tokensStart, self, err )
+                if self.failAction:
+                    if err is None:
+                        err = sys.exc_info()[1]
+                    self.failAction( instring, tokensStart, self, err )
+                raise
+        else:
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = loc
+            if self.mayIndexError or loc >= len(instring):
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            else:
+                loc,tokens = self.parseImpl( instring, preloc, doActions )
+
+        tokens = self.postParse( instring, loc, tokens )
+
+        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
+        if self.parseAction and (doActions or self.callDuringTry):
+            if debugging:
+                try:
+                    for fn in self.parseAction:
+                        tokens = fn( instring, tokensStart, retTokens )
+                        if tokens is not None:
+                            retTokens = ParseResults( tokens,
+                                                      self.resultsName,
+                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                      modal=self.modalResults )
+                except ParseBaseException:
+                    #~ print "Exception raised in user parse action:", err
+                    if (self.debugActions[2] ):
+                        err = sys.exc_info()[1]
+                        self.debugActions[2]( instring, tokensStart, self, err )
+                    raise
+            else:
+                for fn in self.parseAction:
+                    tokens = fn( instring, tokensStart, retTokens )
+                    if tokens is not None:
+                        retTokens = ParseResults( tokens,
+                                                  self.resultsName,
+                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                  modal=self.modalResults )
+
+        if debugging:
+            #~ print ("Matched",self,"->",retTokens.asList())
+            if (self.debugActions[1] ):
+                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
+
+        return loc, retTokens
+
+    def tryParse( self, instring, loc ):
+        try:
+            return self._parse( instring, loc, doActions=False )[0]
+        except ParseFatalException:
+            raise ParseException( instring, loc, self.errmsg, self)
+
+    # this method gets repeatedly called during backtracking with the same arguments -
+    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
+    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
+        lookup = (self,instring,loc,callPreParse,doActions)
+        if lookup in ParserElement._exprArgCache:
+            value = ParserElement._exprArgCache[ lookup ]
+            if isinstance(value,Exception):
+                raise value
+            return value
+        else:
+            try:
+                value = self._parseNoCache( instring, loc, doActions, callPreParse )
+                ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
+                return value
+            except ParseBaseException:
+                pe = sys.exc_info()[1]
+                ParserElement._exprArgCache[ lookup ] = pe
+                raise
+
+    _parse = _parseNoCache
+
+    # argument cache for optimizing repeated calls when backtracking through recursive expressions
+    _exprArgCache = {}
+    def resetCache():
+        ParserElement._exprArgCache.clear()
+    resetCache = staticmethod(resetCache)
+
+    _packratEnabled = False
+    def enablePackrat():
+        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
+           Repeated parse attempts at the same string location (which happens
+           often in many complex grammars) can immediately return a cached value,
+           instead of re-executing parsing/validating code.  Memoizing is done of
+           both valid results and parsing exceptions.
+
+           This speedup may break existing programs that use parse actions that
+           have side-effects.  For this reason, packrat parsing is disabled when
+           you first import pyparsing.  To activate the packrat feature, your
+           program must call the class method ParserElement.enablePackrat().  If
+           your program uses psyco to "compile as you go", you must call
+           enablePackrat before calling psyco.full().  If you do not do this,
+           Python will crash.  For best results, call enablePackrat() immediately
+           after importing pyparsing.
+        """
+        if not ParserElement._packratEnabled:
+            ParserElement._packratEnabled = True
+            ParserElement._parse = ParserElement._parseCache
+    enablePackrat = staticmethod(enablePackrat)
+
+    def parseString( self, instring, parseAll=False ):
+        """Execute the parse expression with the given string.
+           This is the main interface to the client code, once the complete
+           expression has been built.
+
+           If you want the grammar to require that the entire input string be
+           successfully parsed, then set parseAll to True (equivalent to ending
+           the grammar with StringEnd()).
+
+           Note: parseString implicitly calls expandtabs() on the input string,
+           in order to report proper column numbers in parse actions.
+           If the input string contains tabs and
+           the grammar uses parse actions that use the loc argument to index into the
+           string being parsed, you can ensure you have a consistent view of the input
+           string by:
+            - calling parseWithTabs on your grammar before calling parseString
+              (see L{I{parseWithTabs}<parseWithTabs>})
+            - define your parse action using the full (s,loc,toks) signature, and
+              reference the input string using the parse action's s argument
+            - explictly expand the tabs in your input string before calling
+              parseString
+        """
+        ParserElement.resetCache()
+        if not self.streamlined:
+            self.streamline()
+            #~ self.saveAsList = True
+        for e in self.ignoreExprs:
+            e.streamline()
+        if not self.keepTabs:
+            instring = instring.expandtabs()
+        try:
+            loc, tokens = self._parse( instring, 0 )
+            if parseAll:
+                loc = self.preParse( instring, loc )
+                StringEnd()._parse( instring, loc )
+        except ParseBaseException:
+            exc = sys.exc_info()[1]
+            # catch and re-raise exception from here, clears out pyparsing internal stack trace
+            raise exc
+        else:
+            return tokens
+
+    def scanString( self, instring, maxMatches=_MAX_INT ):
+        """Scan the input string for expression matches.  Each match will return the
+           matching tokens, start location, and end location.  May be called with optional
+           maxMatches argument, to clip scanning after 'n' matches are found.
+
+           Note that the start and end locations are reported relative to the string
+           being parsed.  See L{I{parseString}<parseString>} for more information on parsing
+           strings with embedded tabs."""
+        if not self.streamlined:
+            self.streamline()
+        for e in self.ignoreExprs:
+            e.streamline()
+
+        if not self.keepTabs:
+            instring = _ustr(instring).expandtabs()
+        instrlen = len(instring)
+        loc = 0
+        preparseFn = self.preParse
+        parseFn = self._parse
+        ParserElement.resetCache()
+        matches = 0
+        try:
+            while loc <= instrlen and matches < maxMatches:
+                try:
+                    preloc = preparseFn( instring, loc )
+                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
+                except ParseException:
+                    loc = preloc+1
+                else:
+                    if nextLoc > loc:
+                        matches += 1
+                        yield tokens, preloc, nextLoc
+                        loc = nextLoc
+                    else:
+                        loc = preloc+1
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def transformString( self, instring ):
+        """Extension to scanString, to modify matching text with modified tokens that may
+           be returned from a parse action.  To use transformString, define a grammar and
+           attach a parse action to it that modifies the returned token list.
+           Invoking transformString() on a target string will then scan for matches,
+           and replace the matched text patterns according to the logic in the parse
+           action.  transformString() returns the resulting transformed string."""
+        out = []
+        lastE = 0
+        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
+        # keep string locs straight between transformString and scanString
+        self.keepTabs = True
+        try:
+            for t,s,e in self.scanString( instring ):
+                out.append( instring[lastE:s] )
+                if t:
+                    if isinstance(t,ParseResults):
+                        out += t.asList()
+                    elif isinstance(t,list):
+                        out += t
+                    else:
+                        out.append(t)
+                lastE = e
+            out.append(instring[lastE:])
+            return "".join(map(_ustr,out))
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def searchString( self, instring, maxMatches=_MAX_INT ):
+        """Another extension to scanString, simplifying the access to the tokens found
+           to match the given parse expression.  May be called with optional
+           maxMatches argument, to clip searching after 'n' matches are found.
+        """
+        try:
+            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def __add__(self, other ):
+        """Implementation of + operator - returns And"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, other ] )
+
+    def __radd__(self, other ):
+        """Implementation of + operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other + self
+
+    def __sub__(self, other):
+        """Implementation of - operator, returns And with error stop"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, And._ErrorStop(), other ] )
+
+    def __rsub__(self, other ):
+        """Implementation of - operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other - self
+
+    def __mul__(self,other):
+        if isinstance(other,int):
+            minElements, optElements = other,0
+        elif isinstance(other,tuple):
+            other = (other + (None, None))[:2]
+            if other[0] is None:
+                other = (0, other[1])
+            if isinstance(other[0],int) and other[1] is None:
+                if other[0] == 0:
+                    return ZeroOrMore(self)
+                if other[0] == 1:
+                    return OneOrMore(self)
+                else:
+                    return self*other[0] + ZeroOrMore(self)
+            elif isinstance(other[0],int) and isinstance(other[1],int):
+                minElements, optElements = other
+                optElements -= minElements
+            else:
+                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
+        else:
+            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
+
+        if minElements < 0:
+            raise ValueError("cannot multiply ParserElement by negative value")
+        if optElements < 0:
+            raise ValueError("second tuple value must be greater or equal to first tuple value")
+        if minElements == optElements == 0:
+            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
+
+        if (optElements):
+            def makeOptionalList(n):
+                if n>1:
+                    return Optional(self + makeOptionalList(n-1))
+                else:
+                    return Optional(self)
+            if minElements:
+                if minElements == 1:
+                    ret = self + makeOptionalList(optElements)
+                else:
+                    ret = And([self]*minElements) + makeOptionalList(optElements)
+            else:
+                ret = makeOptionalList(optElements)
+        else:
+            if minElements == 1:
+                ret = self
+            else:
+                ret = And([self]*minElements)
+        return ret
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __or__(self, other ):
+        """Implementation of | operator - returns MatchFirst"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return MatchFirst( [ self, other ] )
+
+    def __ror__(self, other ):
+        """Implementation of | operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other | self
+
+    def __xor__(self, other ):
+        """Implementation of ^ operator - returns Or"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Or( [ self, other ] )
+
+    def __rxor__(self, other ):
+        """Implementation of ^ operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other ^ self
+
+    def __and__(self, other ):
+        """Implementation of & operator - returns Each"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Each( [ self, other ] )
+
+    def __rand__(self, other ):
+        """Implementation of & operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other & self
+
+    def __invert__( self ):
+        """Implementation of ~ operator - returns NotAny"""
+        return NotAny( self )
+
+    def __call__(self, name):
+        """Shortcut for setResultsName, with listAllMatches=default::
+             userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
+           could be written as::
+             userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
+           """
+        return self.setResultsName(name)
+
+    def suppress( self ):
+        """Suppresses the output of this ParserElement; useful to keep punctuation from
+           cluttering up returned output.
+        """
+        return Suppress( self )
+
+    def leaveWhitespace( self ):
+        """Disables the skipping of whitespace before matching the characters in the
+           ParserElement's defined pattern.  This is normally only used internally by
+           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
+        """
+        self.skipWhitespace = False
+        return self
+
+    def setWhitespaceChars( self, chars ):
+        """Overrides the default whitespace chars
+        """
+        self.skipWhitespace = True
+        self.whiteChars = chars
+        self.copyDefaultWhiteChars = False
+        return self
+
+    def parseWithTabs( self ):
+        """Overrides default behavior to expand <TAB>s to spaces before parsing the input string.
+           Must be called before parseString when the input grammar contains elements that
+           match <TAB> characters."""
+        self.keepTabs = True
+        return self
+
+    def ignore( self, other ):
+        """Define expression to be ignored (e.g., comments) while doing pattern
+           matching; may be called repeatedly, to define multiple comment or other
+           ignorable patterns.
+        """
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                self.ignoreExprs.append( other )
+        else:
+            self.ignoreExprs.append( Suppress( other ) )
+        return self
+
+    def setDebugActions( self, startAction, successAction, exceptionAction ):
+        """Enable display of debugging messages while doing pattern matching."""
+        self.debugActions = (startAction or _defaultStartDebugAction,
+                             successAction or _defaultSuccessDebugAction,
+                             exceptionAction or _defaultExceptionDebugAction)
+        self.debug = True
+        return self
+
+    def setDebug( self, flag=True ):
+        """Enable display of debugging messages while doing pattern matching.
+           Set flag to True to enable, False to disable."""
+        if flag:
+            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
+        else:
+            self.debug = False
+        return self
+
+    def __str__( self ):
+        return self.name
+
+    def __repr__( self ):
+        return _ustr(self)
+
+    def streamline( self ):
+        self.streamlined = True
+        self.strRepr = None
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        pass
+
+    def validate( self, validateTrace=[] ):
+        """Check defined expressions for valid structure, check for infinite recursive definitions."""
+        self.checkRecursion( [] )
+
+    def parseFile( self, file_or_filename, parseAll=False ):
+        """Execute the parse expression on the given file or filename.
+           If a filename is specified (instead of a file object),
+           the entire file is opened, read, and closed before parsing.
+        """
+        try:
+            file_contents = file_or_filename.read()
+        except AttributeError:
+            f = open(file_or_filename, "rb")
+            file_contents = f.read()
+            f.close()
+        try:
+            return self.parseString(file_contents, parseAll)
+        except ParseBaseException:
+            # catch and re-raise exception from here, clears out pyparsing internal stack trace
+            exc = sys.exc_info()[1]
+            raise exc
+
+    def getException(self):
+        return ParseException("",0,self.errmsg,self)
+
+    def __getattr__(self,aname):
+        if aname == "myException":
+            self.myException = ret = self.getException();
+            return ret;
+        else:
+            raise AttributeError("no such attribute " + aname)
+
+    def __eq__(self,other):
+        if isinstance(other, ParserElement):
+            return self is other or self.__dict__ == other.__dict__
+        elif isinstance(other, basestring):
+            try:
+                self.parseString(_ustr(other), parseAll=True)
+                return True
+            except ParseBaseException:
+                return False
+        else:
+            return super(ParserElement,self)==other
+
+    def __ne__(self,other):
+        return not (self == other)
+
+    def __hash__(self):
+        return hash(id(self))
+
+    def __req__(self,other):
+        return self == other
+
+    def __rne__(self,other):
+        return not (self == other)
+
+
+class Token(ParserElement):
+    """Abstract ParserElement subclass, for defining atomic matching patterns."""
+    def __init__( self ):
+        super(Token,self).__init__( savelist=False )
+        #self.myException = ParseException("",0,"",self)
+
+    def setName(self, name):
+        s = super(Token,self).setName(name)
+        self.errmsg = "Expected " + self.name
+        #s.myException.msg = self.errmsg
+        return s
+
+
+class Empty(Token):
+    """An empty token, will always match."""
+    def __init__( self ):
+        super(Empty,self).__init__()
+        self.name = "Empty"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+
+class NoMatch(Token):
+    """A token that will never match."""
+    def __init__( self ):
+        super(NoMatch,self).__init__()
+        self.name = "NoMatch"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.errmsg = "Unmatchable token"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+
+class Literal(Token):
+    """Token to exactly match a specified string."""
+    def __init__( self, matchString ):
+        super(Literal,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Literal; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+            self.__class__ = Empty
+        self.name = '"%s"' % _ustr(self.match)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+
+    # Performance tuning: this routine gets called a *lot*
+    # if this is a single character match string  and the first character matches,
+    # short-circuit as quickly as possible, and avoid calling startswith
+    #~ @profile
+    def parseImpl( self, instring, loc, doActions=True ):
+        if (instring[loc] == self.firstMatchChar and
+            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
+            return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+_L = Literal
+
+class Keyword(Token):
+    """Token to exactly match a specified string as a keyword, that is, it must be
+       immediately followed by a non-keyword character.  Compare with Literal::
+         Literal("if") will match the leading 'if' in 'ifAndOnlyIf'.
+         Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)'
+       Accepts two optional constructor arguments in addition to the keyword string:
+       identChars is a string of characters that would be valid identifier characters,
+       defaulting to all alphanumerics + "_" and "$"; caseless allows case-insensitive
+       matching, default is False.
+    """
+    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
+
+    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
+        super(Keyword,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Keyword; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+        self.name = '"%s"' % self.match
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.caseless = caseless
+        if caseless:
+            self.caselessmatch = matchString.upper()
+            identChars = identChars.upper()
+        self.identChars = _str2dict(identChars)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.caseless:
+            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
+                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        else:
+            if (instring[loc] == self.firstMatchChar and
+                (self.matchLen==1 or instring.startswith(self.match,loc)) and
+                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
+                (loc == 0 or instring[loc-1] not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+    def copy(self):
+        c = super(Keyword,self).copy()
+        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        return c
+
+    def setDefaultKeywordChars( chars ):
+        """Overrides the default Keyword chars
+        """
+        Keyword.DEFAULT_KEYWORD_CHARS = chars
+    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
+
+class CaselessLiteral(Literal):
+    """Token to match a specified string, ignoring case of letters.
+       Note: the matched results will always be in the case of the given
+       match string, NOT the case of the input text.
+    """
+    def __init__( self, matchString ):
+        super(CaselessLiteral,self).__init__( matchString.upper() )
+        # Preserve the defining literal.
+        self.returnString = matchString
+        self.name = "'%s'" % self.returnString
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[ loc:loc+self.matchLen ].upper() == self.match:
+            return loc+self.matchLen, self.returnString
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class CaselessKeyword(Keyword):
+    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
+        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
+            return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class Word(Token):
+    """Token for matching words composed of allowed character sets.
+       Defined with string containing all allowed initial characters,
+       an optional string containing allowed body characters (if omitted,
+       defaults to the initial character set), and an optional minimum,
+       maximum, and/or exact length.  The default value for min is 1 (a
+       minimum value < 1 is not valid); the default values for max and exact
+       are 0, meaning no maximum or exact length restriction.
+    """
+    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ):
+        super(Word,self).__init__()
+        self.initCharsOrig = initChars
+        self.initChars = _str2dict(initChars)
+        if bodyChars :
+            self.bodyCharsOrig = bodyChars
+            self.bodyChars = _str2dict(bodyChars)
+        else:
+            self.bodyCharsOrig = initChars
+            self.bodyChars = _str2dict(initChars)
+
+        self.maxSpecified = max > 0
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.asKeyword = asKeyword
+
+        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
+            if self.bodyCharsOrig == self.initCharsOrig:
+                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
+            elif len(self.bodyCharsOrig) == 1:
+                self.reString = "%s[%s]*" % \
+                                      (re.escape(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            else:
+                self.reString = "[%s][%s]*" % \
+                                      (_escapeRegexRangeChars(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            if self.asKeyword:
+                self.reString = r"\b"+self.reString+r"\b"
+            try:
+                self.re = re.compile( self.reString )
+            except:
+                self.re = None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.re:
+            result = self.re.match(instring,loc)
+            if not result:
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+
+            loc = result.end()
+            return loc,result.group()
+
+        if not(instring[ loc ] in self.initChars):
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        start = loc
+        loc += 1
+        instrlen = len(instring)
+        bodychars = self.bodyChars
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, instrlen )
+        while loc < maxloc and instring[loc] in bodychars:
+            loc += 1
+
+        throwException = False
+        if loc - start < self.minLen:
+            throwException = True
+        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
+            throwException = True
+        if self.asKeyword:
+            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
+                throwException = True
+
+        if throwException:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(Word,self).__str__()
+        except:
+            pass
+
+
+        if self.strRepr is None:
+
+            def charsAsStr(s):
+                if len(s)>4:
+                    return s[:4]+"..."
+                else:
+                    return s
+
+            if ( self.initCharsOrig != self.bodyCharsOrig ):
+                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
+            else:
+                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
+
+        return self.strRepr
+
+
+class Regex(Token):
+    """Token for matching strings that match a given regular expression.
+       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
+    """
+    def __init__( self, pattern, flags=0):
+        """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags."""
+        super(Regex,self).__init__()
+
+        if len(pattern) == 0:
+            warnings.warn("null string passed to Regex; use Empty() instead",
+                    SyntaxWarning, stacklevel=2)
+
+        self.pattern = pattern
+        self.flags = flags
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = self.re.match(instring,loc)
+        if not result:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        loc = result.end()
+        d = result.groupdict()
+        ret = ParseResults(result.group())
+        if d:
+            for k in d:
+                ret[k] = d[k]
+        return loc,ret
+
+    def __str__( self ):
+        try:
+            return super(Regex,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "Re:(%s)" % repr(self.pattern)
+
+        return self.strRepr
+
+
+class QuotedString(Token):
+    """Token for matching strings that are delimited by quoting characters.
+    """
+    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
+        """
+           Defined with the following parameters:
+            - quoteChar - string of one or more characters defining the quote delimiting string
+            - escChar - character to escape quotes, typically backslash (default=None)
+            - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
+            - multiline - boolean indicating whether quotes can span multiple lines (default=False)
+            - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
+            - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
+        """
+        super(QuotedString,self).__init__()
+
+        # remove white space from quote chars - wont work anyway
+        quoteChar = quoteChar.strip()
+        if len(quoteChar) == 0:
+            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+            raise SyntaxError()
+
+        if endQuoteChar is None:
+            endQuoteChar = quoteChar
+        else:
+            endQuoteChar = endQuoteChar.strip()
+            if len(endQuoteChar) == 0:
+                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+                raise SyntaxError()
+
+        self.quoteChar = quoteChar
+        self.quoteCharLen = len(quoteChar)
+        self.firstQuoteChar = quoteChar[0]
+        self.endQuoteChar = endQuoteChar
+        self.endQuoteCharLen = len(endQuoteChar)
+        self.escChar = escChar
+        self.escQuote = escQuote
+        self.unquoteResults = unquoteResults
+
+        if multiline:
+            self.flags = re.MULTILINE | re.DOTALL
+            self.pattern = r'%s(?:[^%s%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        else:
+            self.flags = 0
+            self.pattern = r'%s(?:[^%s\n\r%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        if len(self.endQuoteChar) > 1:
+            self.pattern += (
+                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
+                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
+                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
+                )
+        if escQuote:
+            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
+        if escChar:
+            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
+            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
+        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
+        if not result:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        loc = result.end()
+        ret = result.group()
+
+        if self.unquoteResults:
+
+            # strip off quotes
+            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
+
+            if isinstance(ret,basestring):
+                # replace escaped characters
+                if self.escChar:
+                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
+
+                # replace escaped quotes
+                if self.escQuote:
+                    ret = ret.replace(self.escQuote, self.endQuoteChar)
+
+        return loc, ret
+
+    def __str__( self ):
+        try:
+            return super(QuotedString,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
+
+        return self.strRepr
+
+
+class CharsNotIn(Token):
+    """Token for matching words composed of characters *not* in a given set.
+       Defined with string containing all disallowed characters, and an optional
+       minimum, maximum, and/or exact length.  The default value for min is 1 (a
+       minimum value < 1 is not valid); the default values for max and exact
+       are 0, meaning no maximum or exact length restriction.
+    """
+    def __init__( self, notChars, min=1, max=0, exact=0 ):
+        super(CharsNotIn,self).__init__()
+        self.skipWhitespace = False
+        self.notChars = notChars
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = ( self.minLen == 0 )
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[loc] in self.notChars:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        start = loc
+        loc += 1
+        notchars = self.notChars
+        maxlen = min( start+self.maxLen, len(instring) )
+        while loc < maxlen and \
+              (instring[loc] not in notchars):
+            loc += 1
+
+        if loc - start < self.minLen:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(CharsNotIn, self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            if len(self.notChars) > 4:
+                self.strRepr = "!W:(%s...)" % self.notChars[:4]
+            else:
+                self.strRepr = "!W:(%s)" % self.notChars
+
+        return self.strRepr
+
+class White(Token):
+    """Special matching class for matching whitespace.  Normally, whitespace is ignored
+       by pyparsing grammars.  This class is included when some whitespace structures
+       are significant.  Define with a string containing the whitespace characters to be
+       matched; default is " \\t\\r\\n".  Also takes optional min, max, and exact arguments,
+       as defined for the Word class."""
+    whiteStrs = {
+        " " : "<SPC>",
+        "\t": "<TAB>",
+        "\n": "<LF>",
+        "\r": "<CR>",
+        "\f": "<FF>",
+        }
+    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
+        super(White,self).__init__()
+        self.matchWhite = ws
+        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
+        #~ self.leaveWhitespace()
+        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
+        self.mayReturnEmpty = True
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not(instring[ loc ] in self.matchWhite):
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        start = loc
+        loc += 1
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, len(instring) )
+        while loc < maxloc and instring[loc] in self.matchWhite:
+            loc += 1
+
+        if loc - start < self.minLen:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+
+class _PositionToken(Token):
+    def __init__( self ):
+        super(_PositionToken,self).__init__()
+        self.name=self.__class__.__name__
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+class GoToColumn(_PositionToken):
+    """Token to advance to a specific column of input text; useful for tabular report scraping."""
+    def __init__( self, colno ):
+        super(GoToColumn,self).__init__()
+        self.col = colno
+
+    def preParse( self, instring, loc ):
+        if col(loc,instring) != self.col:
+            instrlen = len(instring)
+            if self.ignoreExprs:
+                loc = self._skipIgnorables( instring, loc )
+            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
+                loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        thiscol = col( loc, instring )
+        if thiscol > self.col:
+            raise ParseException( instring, loc, "Text not in expected column", self )
+        newloc = loc + self.col - thiscol
+        ret = instring[ loc: newloc ]
+        return newloc, ret
+
+class LineStart(_PositionToken):
+    """Matches if current position is at the beginning of a line within the parse string"""
+    def __init__( self ):
+        super(LineStart,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected start of line"
+        #self.myException.msg = self.errmsg
+
+    def preParse( self, instring, loc ):
+        preloc = super(LineStart,self).preParse(instring,loc)
+        if instring[preloc] == "\n":
+            loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not( loc==0 or
+            (loc == self.preParse( instring, 0 )) or
+            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
+            #~ raise ParseException( instring, loc, "Expected start of line" )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        return loc, []
+
+class LineEnd(_PositionToken):
+    """Matches if current position is at the end of a line within the parse string"""
+    def __init__( self ):
+        super(LineEnd,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected end of line"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc<len(instring):
+            if instring[loc] == "\n":
+                return loc+1, "\n"
+            else:
+                #~ raise ParseException( instring, loc, "Expected end of line" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        elif loc == len(instring):
+            return loc+1, []
+        else:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+class StringStart(_PositionToken):
+    """Matches if current position is at the beginning of the parse string"""
+    def __init__( self ):
+        super(StringStart,self).__init__()
+        self.errmsg = "Expected start of text"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc != 0:
+            # see if entire string up to here is just whitespace and ignoreables
+            if loc != self.preParse( instring, 0 ):
+                #~ raise ParseException( instring, loc, "Expected start of text" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+class StringEnd(_PositionToken):
+    """Matches if current position is at the end of the parse string"""
+    def __init__( self ):
+        super(StringEnd,self).__init__()
+        self.errmsg = "Expected end of text"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc < len(instring):
+            #~ raise ParseException( instring, loc, "Expected end of text" )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        elif loc == len(instring):
+            return loc+1, []
+        elif loc > len(instring):
+            return loc, []
+        else:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+class WordStart(_PositionToken):
+    """Matches if the current position is at the beginning of a Word, and
+       is not preceded by any character in a given set of wordChars
+       (default=printables). To emulate the \b behavior of regular expressions,
+       use WordStart(alphanums). WordStart will also match at the beginning of
+       the string being parsed, or at the beginning of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordStart,self).__init__()
+        self.wordChars = _str2dict(wordChars)
+        self.errmsg = "Not at the start of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        if loc != 0:
+            if (instring[loc-1] in self.wordChars or
+                instring[loc] not in self.wordChars):
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+class WordEnd(_PositionToken):
+    """Matches if the current position is at the end of a Word, and
+       is not followed by any character in a given set of wordChars
+       (default=printables). To emulate the \b behavior of regular expressions,
+       use WordEnd(alphanums). WordEnd will also match at the end of
+       the string being parsed, or at the end of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordEnd,self).__init__()
+        self.wordChars = _str2dict(wordChars)
+        self.skipWhitespace = False
+        self.errmsg = "Not at the end of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        instrlen = len(instring)
+        if instrlen>0 and loc<instrlen:
+            if (instring[loc] in self.wordChars or
+                instring[loc-1] not in self.wordChars):
+                #~ raise ParseException( instring, loc, "Expected end of word" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+
+class ParseExpression(ParserElement):
+    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
+    def __init__( self, exprs, savelist = False ):
+        super(ParseExpression,self).__init__(savelist)
+        if isinstance( exprs, list ):
+            self.exprs = exprs
+        elif isinstance( exprs, basestring ):
+            self.exprs = [ Literal( exprs ) ]
+        else:
+            try:
+                self.exprs = list( exprs )
+            except TypeError:
+                self.exprs = [ exprs ]
+        self.callPreparse = False
+
+    def __getitem__( self, i ):
+        return self.exprs[i]
+
+    def append( self, other ):
+        self.exprs.append( other )
+        self.strRepr = None
+        return self
+
+    def leaveWhitespace( self ):
+        """Extends leaveWhitespace defined in base class, and also invokes leaveWhitespace on
+           all contained expressions."""
+        self.skipWhitespace = False
+        self.exprs = [ e.copy() for e in self.exprs ]
+        for e in self.exprs:
+            e.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseExpression, self).ignore( other )
+                for e in self.exprs:
+                    e.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseExpression, self).ignore( other )
+            for e in self.exprs:
+                e.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def __str__( self ):
+        try:
+            return super(ParseExpression,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
+        return self.strRepr
+
+    def streamline( self ):
+        super(ParseExpression,self).streamline()
+
+        for e in self.exprs:
+            e.streamline()
+
+        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
+        # but only if there are no parse actions or resultsNames on the nested And's
+        # (likewise for Or's and MatchFirst's)
+        if ( len(self.exprs) == 2 ):
+            other = self.exprs[0]
+            if ( isinstance( other, self.__class__ ) and
+                  not(other.parseAction) and
+                  other.resultsName is None and
+                  not other.debug ):
+                self.exprs = other.exprs[:] + [ self.exprs[1] ]
+                self.strRepr = None
+                self.mayReturnEmpty |= other.mayReturnEmpty
+                self.mayIndexError  |= other.mayIndexError
+
+            other = self.exprs[-1]
+            if ( isinstance( other, self.__class__ ) and
+                  not(other.parseAction) and
+                  other.resultsName is None and
+                  not other.debug ):
+                self.exprs = self.exprs[:-1] + other.exprs[:]
+                self.strRepr = None
+                self.mayReturnEmpty |= other.mayReturnEmpty
+                self.mayIndexError  |= other.mayIndexError
+
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
+        return ret
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        for e in self.exprs:
+            e.validate(tmp)
+        self.checkRecursion( [] )
+
+class And(ParseExpression):
+    """Requires all given ParseExpressions to be found in the given order.
+       Expressions may be separated by whitespace.
+       May be constructed using the '+' operator.
+    """
+
+    class _ErrorStop(Empty):
+        def __init__(self, *args, **kwargs):
+            super(Empty,self).__init__(*args, **kwargs)
+            self.leaveWhitespace()
+
+    def __init__( self, exprs, savelist = True ):
+        super(And,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = True
+        for e in self.exprs:
+            if not e.mayReturnEmpty:
+                self.mayReturnEmpty = False
+                break
+        self.setWhitespaceChars( exprs[0].whiteChars )
+        self.skipWhitespace = exprs[0].skipWhitespace
+        self.callPreparse = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        # pass False as last arg to _parse for first element, since we already
+        # pre-parsed the string as part of our And pre-parsing
+        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
+        errorStop = False
+        for e in self.exprs[1:]:
+            if isinstance(e, And._ErrorStop):
+                errorStop = True
+                continue
+            if errorStop:
+                try:
+                    loc, exprtokens = e._parse( instring, loc, doActions )
+                except ParseSyntaxException:
+                    raise
+                except ParseBaseException:
+                    pe = sys.exc_info()[1]
+                    raise ParseSyntaxException(pe)
+                except IndexError:
+                    raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
+            else:
+                loc, exprtokens = e._parse( instring, loc, doActions )
+            if exprtokens or exprtokens.keys():
+                resultlist += exprtokens
+        return loc, resultlist
+
+    def __iadd__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #And( [ self, other ] )
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+            if not e.mayReturnEmpty:
+                break
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+
+class Or(ParseExpression):
+    """Requires that at least one ParseExpression is found.
+       If two expressions match, the expression that matches the longest string will be used.
+       May be constructed using the '^' operator.
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(Or,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = False
+        for e in self.exprs:
+            if e.mayReturnEmpty:
+                self.mayReturnEmpty = True
+                break
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxMatchLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                loc2 = e.tryParse( instring, loc )
+            except ParseException:
+                err = sys.exc_info()[1]
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+            else:
+                if loc2 > maxMatchLoc:
+                    maxMatchLoc = loc2
+                    maxMatchExp = e
+
+        if maxMatchLoc < 0:
+            if maxException is not None:
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+        return maxMatchExp._parse( instring, loc, doActions )
+
+    def __ixor__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #Or( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class MatchFirst(ParseExpression):
+    """Requires that at least one ParseExpression is found.
+       If two expressions match, the first one listed is the one that will match.
+       May be constructed using the '|' operator.
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(MatchFirst,self).__init__(exprs, savelist)
+        if exprs:
+            self.mayReturnEmpty = False
+            for e in self.exprs:
+                if e.mayReturnEmpty:
+                    self.mayReturnEmpty = True
+                    break
+        else:
+            self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                ret = e._parse( instring, loc, doActions )
+                return ret
+            except ParseException, err:
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+
+        # only got here if no expression matched, raise exception for match that made it the furthest
+        else:
+            if maxException is not None:
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+    def __ior__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #MatchFirst( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class Each(ParseExpression):
+    """Requires all given ParseExpressions to be found, but in any order.
+       Expressions may be separated by whitespace.
+       May be constructed using the '&' operator.
+    """
+    def __init__( self, exprs, savelist = True ):
+        super(Each,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = True
+        for e in self.exprs:
+            if not e.mayReturnEmpty:
+                self.mayReturnEmpty = False
+                break
+        self.skipWhitespace = True
+        self.initExprGroups = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.initExprGroups:
+            self.optionals = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
+            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
+            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
+            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
+            self.required += self.multirequired
+            self.initExprGroups = False
+        tmpLoc = loc
+        tmpReqd = self.required[:]
+        tmpOpt  = self.optionals[:]
+        matchOrder = []
+
+        keepMatching = True
+        while keepMatching:
+            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
+            failed = []
+            for e in tmpExprs:
+                try:
+                    tmpLoc = e.tryParse( instring, tmpLoc )
+                except ParseException:
+                    failed.append(e)
+                else:
+                    matchOrder.append(e)
+                    if e in tmpReqd:
+                        tmpReqd.remove(e)
+                    elif e in tmpOpt:
+                        tmpOpt.remove(e)
+            if len(failed) == len(tmpExprs):
+                keepMatching = False
+
+        if tmpReqd:
+            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
+            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
+
+        # add any unmatched Optionals, in case they have default values defined
+        matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt)
+
+        resultlist = []
+        for e in matchOrder:
+            loc,results = e._parse(instring,loc,doActions)
+            resultlist.append(results)
+
+        finalResults = ParseResults([])
+        for r in resultlist:
+            dups = {}
+            for k in r.keys():
+                if k in finalResults.keys():
+                    tmp = ParseResults(finalResults[k])
+                    tmp += ParseResults(r[k])
+                    dups[k] = tmp
+            finalResults += ParseResults(r)
+            for k,v in dups.items():
+                finalResults[k] = v
+        return loc, finalResults
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class ParseElementEnhance(ParserElement):
+    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
+    def __init__( self, expr, savelist=False ):
+        super(ParseElementEnhance,self).__init__(savelist)
+        if isinstance( expr, basestring ):
+            expr = Literal(expr)
+        self.expr = expr
+        self.strRepr = None
+        if expr is not None:
+            self.mayIndexError = expr.mayIndexError
+            self.mayReturnEmpty = expr.mayReturnEmpty
+            self.setWhitespaceChars( expr.whiteChars )
+            self.skipWhitespace = expr.skipWhitespace
+            self.saveAsList = expr.saveAsList
+            self.callPreparse = expr.callPreparse
+            self.ignoreExprs.extend(expr.ignoreExprs)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr is not None:
+            return self.expr._parse( instring, loc, doActions, callPreParse=False )
+        else:
+            raise ParseException("",loc,self.errmsg,self)
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        self.expr = self.expr.copy()
+        if self.expr is not None:
+            self.expr.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseElementEnhance, self).ignore( other )
+                if self.expr is not None:
+                    self.expr.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseElementEnhance, self).ignore( other )
+            if self.expr is not None:
+                self.expr.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def streamline( self ):
+        super(ParseElementEnhance,self).streamline()
+        if self.expr is not None:
+            self.expr.streamline()
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        if self in parseElementList:
+            raise RecursiveGrammarException( parseElementList+[self] )
+        subRecCheckList = parseElementList[:] + [ self ]
+        if self.expr is not None:
+            self.expr.checkRecursion( subRecCheckList )
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        if self.expr is not None:
+            self.expr.validate(tmp)
+        self.checkRecursion( [] )
+
+    def __str__( self ):
+        try:
+            return super(ParseElementEnhance,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None and self.expr is not None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
+        return self.strRepr
+
+
+class FollowedBy(ParseElementEnhance):
+    """Lookahead matching of the given parse expression.  FollowedBy
+    does *not* advance the parsing position within the input string, it only
+    verifies that the specified parse expression matches at the current
+    position.  FollowedBy always returns a null token list."""
+    def __init__( self, expr ):
+        super(FollowedBy,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self.expr.tryParse( instring, loc )
+        return loc, []
+
+
+class NotAny(ParseElementEnhance):
+    """Lookahead to disallow matching with the given parse expression.  NotAny
+    does *not* advance the parsing position within the input string, it only
+    verifies that the specified parse expression does *not* match at the current
+    position.  Also, NotAny does *not* skip over leading whitespace. NotAny
+    always returns a null token list.  May be constructed using the '~' operator."""
+    def __init__( self, expr ):
+        super(NotAny,self).__init__(expr)
+        #~ self.leaveWhitespace()
+        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
+        self.mayReturnEmpty = True
+        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
+        #self.myException = ParseException("",0,self.errmsg,self)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            self.expr.tryParse( instring, loc )
+        except (ParseException,IndexError):
+            pass
+        else:
+            #~ raise ParseException(instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "~{" + _ustr(self.expr) + "}"
+
+        return self.strRepr
+
+
+class ZeroOrMore(ParseElementEnhance):
+    """Optional repetition of zero or more of the given expression."""
+    def __init__( self, expr ):
+        super(ZeroOrMore,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        tokens = []
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
+            while 1:
+                if hasIgnoreExprs:
+                    preloc = self._skipIgnorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.keys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]..."
+
+        return self.strRepr
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
+        ret.saveAsList = True
+        return ret
+
+
+class OneOrMore(ParseElementEnhance):
+    """Repetition of one or more of the given expression."""
+    def parseImpl( self, instring, loc, doActions=True ):
+        # must be at least one
+        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        try:
+            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
+            while 1:
+                if hasIgnoreExprs:
+                    preloc = self._skipIgnorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.keys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + _ustr(self.expr) + "}..."
+
+        return self.strRepr
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
+        ret.saveAsList = True
+        return ret
+
+class _NullToken(object):
+    def __bool__(self):
+        return False
+    __nonzero__ = __bool__
+    def __str__(self):
+        return ""
+
+_optionalNotMatched = _NullToken()
+class Optional(ParseElementEnhance):
+    """Optional matching of the given expression.
+       A default return string can also be specified, if the optional expression
+       is not found.
+    """
+    def __init__( self, exprs, default=_optionalNotMatched ):
+        super(Optional,self).__init__( exprs, savelist=False )
+        self.defaultValue = default
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        except (ParseException,IndexError):
+            if self.defaultValue is not _optionalNotMatched:
+                if self.expr.resultsName:
+                    tokens = ParseResults([ self.defaultValue ])
+                    tokens[self.expr.resultsName] = self.defaultValue
+                else:
+                    tokens = [ self.defaultValue ]
+            else:
+                tokens = []
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]"
+
+        return self.strRepr
+
+
+class SkipTo(ParseElementEnhance):
+    """Token for skipping over all undefined text until the matched expression is found.
+       If include is set to true, the matched expression is also parsed (the skipped text
+       and matched expression are returned as a 2-element list).  The ignore
+       argument is used to define grammars (typically quoted strings and comments) that
+       might contain false matches.
+    """
+    def __init__( self, other, include=False, ignore=None, failOn=None ):
+        super( SkipTo, self ).__init__( other )
+        self.ignoreExpr = ignore
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.includeMatch = include
+        self.asList = False
+        if failOn is not None and isinstance(failOn, basestring):
+            self.failOn = Literal(failOn)
+        else:
+            self.failOn = failOn
+        self.errmsg = "No match found for "+_ustr(self.expr)
+        #self.myException = ParseException("",0,self.errmsg,self)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        startLoc = loc
+        instrlen = len(instring)
+        expr = self.expr
+        failParse = False
+        while loc <= instrlen:
+            try:
+                if self.failOn:
+                    try:
+                        self.failOn.tryParse(instring, loc)
+                    except ParseBaseException:
+                        pass
+                    else:
+                        failParse = True
+                        raise ParseException(instring, loc, "Found expression " + str(self.failOn))
+                    failParse = False
+                if self.ignoreExpr is not None:
+                    while 1:
+                        try:
+                            loc = self.ignoreExpr.tryParse(instring,loc)
+                            # print "found ignoreExpr, advance to", loc
+                        except ParseBaseException:
+                            break
+                expr._parse( instring, loc, doActions=False, callPreParse=False )
+                skipText = instring[startLoc:loc]
+                if self.includeMatch:
+                    loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
+                    if mat:
+                        skipRes = ParseResults( skipText )
+                        skipRes += mat
+                        return loc, [ skipRes ]
+                    else:
+                        return loc, [ skipText ]
+                else:
+                    return loc, [ skipText ]
+            except (ParseException,IndexError):
+                if failParse:
+                    raise
+                else:
+                    loc += 1
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class Forward(ParseElementEnhance):
+    """Forward declaration of an expression to be defined later -
+       used for recursive grammars, such as algebraic infix notation.
+       When the expression is known, it is assigned to the Forward variable using the '<<' operator.
+
+       Note: take care when assigning to Forward not to overlook precedence of operators.
+       Specifically, '|' has a lower precedence than '<<', so that::
+          fwdExpr << a | b | c
+       will actually be evaluated as::
+          (fwdExpr << a) | b | c
+       thereby leaving b and c out as parseable alternatives.  It is recommended that you
+       explicitly group the values inserted into the Forward::
+          fwdExpr << (a | b | c)
+    """
+    def __init__( self, other=None ):
+        super(Forward,self).__init__( other, savelist=False )
+
+    def __lshift__( self, other ):
+        if isinstance( other, basestring ):
+            other = Literal(other)
+        self.expr = other
+        self.mayReturnEmpty = other.mayReturnEmpty
+        self.strRepr = None
+        self.mayIndexError = self.expr.mayIndexError
+        self.mayReturnEmpty = self.expr.mayReturnEmpty
+        self.setWhitespaceChars( self.expr.whiteChars )
+        self.skipWhitespace = self.expr.skipWhitespace
+        self.saveAsList = self.expr.saveAsList
+        self.ignoreExprs.extend(self.expr.ignoreExprs)
+        return None
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        return self
+
+    def streamline( self ):
+        if not self.streamlined:
+            self.streamlined = True
+            if self.expr is not None:
+                self.expr.streamline()
+        return self
+
+    def validate( self, validateTrace=[] ):
+        if self not in validateTrace:
+            tmp = validateTrace[:]+[self]
+            if self.expr is not None:
+                self.expr.validate(tmp)
+        self.checkRecursion([])
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        self._revertClass = self.__class__
+        self.__class__ = _ForwardNoRecurse
+        try:
+            if self.expr is not None:
+                retString = _ustr(self.expr)
+            else:
+                retString = "None"
+        finally:
+            self.__class__ = self._revertClass
+        return self.__class__.__name__ + ": " + retString
+
+    def copy(self):
+        if self.expr is not None:
+            return super(Forward,self).copy()
+        else:
+            ret = Forward()
+            ret << self
+            return ret
+
+class _ForwardNoRecurse(Forward):
+    def __str__( self ):
+        return "..."
+
+class TokenConverter(ParseElementEnhance):
+    """Abstract subclass of ParseExpression, for converting parsed results."""
+    def __init__( self, expr, savelist=False ):
+        super(TokenConverter,self).__init__( expr )#, savelist )
+        self.saveAsList = False
+
+class Upcase(TokenConverter):
+    """Converter to upper case all matching tokens."""
+    def __init__(self, *args):
+        super(Upcase,self).__init__(*args)
+        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
+                       DeprecationWarning,stacklevel=2)
+
+    def postParse( self, instring, loc, tokenlist ):
+        return list(map( string.upper, tokenlist ))
+
+
+class Combine(TokenConverter):
+    """Converter to concatenate all matching tokens to a single string.
+       By default, the matching patterns must also be contiguous in the input string;
+       this can be disabled by specifying 'adjacent=False' in the constructor.
+    """
+    def __init__( self, expr, joinString="", adjacent=True ):
+        super(Combine,self).__init__( expr )
+        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
+        if adjacent:
+            self.leaveWhitespace()
+        self.adjacent = adjacent
+        self.skipWhitespace = True
+        self.joinString = joinString
+
+    def ignore( self, other ):
+        if self.adjacent:
+            ParserElement.ignore(self, other)
+        else:
+            super( Combine, self).ignore( other )
+        return self
+
+    def postParse( self, instring, loc, tokenlist ):
+        retToks = tokenlist.copy()
+        del retToks[:]
+        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
+
+        if self.resultsName and len(retToks.keys())>0:
+            return [ retToks ]
+        else:
+            return retToks
+
+class Group(TokenConverter):
+    """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions."""
+    def __init__( self, expr ):
+        super(Group,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        return [ tokenlist ]
+
+class Dict(TokenConverter):
+    """Converter to return a repetitive expression as a list, but also as a dictionary.
+       Each element can also be referenced using the first token in the expression as its key.
+       Useful for tabular report scraping when the first column can be used as a item key.
+    """
+    def __init__( self, exprs ):
+        super(Dict,self).__init__( exprs )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        for i,tok in enumerate(tokenlist):
+            if len(tok) == 0:
+                continue
+            ikey = tok[0]
+            if isinstance(ikey,int):
+                ikey = _ustr(tok[0]).strip()
+            if len(tok)==1:
+                tokenlist[ikey] = _ParseResultsWithOffset("",i)
+            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
+                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
+            else:
+                dictvalue = tok.copy() #ParseResults(i)
+                del dictvalue[0]
+                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
+                else:
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
+
+        if self.resultsName:
+            return [ tokenlist ]
+        else:
+            return tokenlist
+
+
+class Suppress(TokenConverter):
+    """Converter for ignoring the results of a parsed expression."""
+    def postParse( self, instring, loc, tokenlist ):
+        return []
+
+    def suppress( self ):
+        return self
+
+
+class OnlyOnce(object):
+    """Wrapper for parse actions, to ensure they are only called once."""
+    def __init__(self, methodCall):
+        self.callable = ParserElement._normalizeParseActionArgs(methodCall)
+        self.called = False
+    def __call__(self,s,l,t):
+        if not self.called:
+            results = self.callable(s,l,t)
+            self.called = True
+            return results
+        raise ParseException(s,l,"")
+    def reset(self):
+        self.called = False
+
+def traceParseAction(f):
+    """Decorator for debugging parse actions."""
+    f = ParserElement._normalizeParseActionArgs(f)
+    def z(*paArgs):
+        thisFunc = f.func_name
+        s,l,t = paArgs[-3:]
+        if len(paArgs)>3:
+            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
+        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
+        try:
+            ret = f(*paArgs)
+        except Exception:
+            exc = sys.exc_info()[1]
+            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
+            raise
+        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
+        return ret
+    try:
+        z.__name__ = f.__name__
+    except AttributeError:
+        pass
+    return z
+
+#
+# global helpers
+#
+def delimitedList( expr, delim=",", combine=False ):
+    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
+       By default, the list elements and delimiters can have intervening whitespace, and
+       comments, but this can be overridden by passing 'combine=True' in the constructor.
+       If combine is set to True, the matching tokens are returned as a single token
+       string, with the delimiters included; otherwise, the matching tokens are returned
+       as a list of tokens, with the delimiters suppressed.
+    """
+    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
+    if combine:
+        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
+    else:
+        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
+
+def countedArray( expr ):
+    """Helper to define a counted list of expressions.
+       This helper defines a pattern of the form::
+           integer expr expr expr...
+       where the leading integer tells how many expr expressions follow.
+       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
+    """
+    arrayExpr = Forward()
+    def countFieldParseAction(s,l,t):
+        n = int(t[0])
+        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
+        return []
+    return ( Word(nums).setName("arrayLen").setParseAction(countFieldParseAction, callDuringTry=True) + arrayExpr )
+
+def _flatten(L):
+    if type(L) is not list: return [L]
+    if L == []: return L
+    return _flatten(L[0]) + _flatten(L[1:])
+
+def matchPreviousLiteral(expr):
+    """Helper to define an expression that is indirectly defined from
+       the tokens matched in a previous expression, that is, it looks
+       for a 'repeat' of a previous expression.  For example::
+           first = Word(nums)
+           second = matchPreviousLiteral(first)
+           matchExpr = first + ":" + second
+       will match "1:1", but not "1:2".  Because this matches a
+       previous literal, will also match the leading "1:1" in "1:10".
+       If this is not desired, use matchPreviousExpr.
+       Do *not* use with packrat parsing enabled.
+    """
+    rep = Forward()
+    def copyTokenToRepeater(s,l,t):
+        if t:
+            if len(t) == 1:
+                rep << t[0]
+            else:
+                # flatten t tokens
+                tflat = _flatten(t.asList())
+                rep << And( [ Literal(tt) for tt in tflat ] )
+        else:
+            rep << Empty()
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    return rep
+
+def matchPreviousExpr(expr):
+    """Helper to define an expression that is indirectly defined from
+       the tokens matched in a previous expression, that is, it looks
+       for a 'repeat' of a previous expression.  For example::
+           first = Word(nums)
+           second = matchPreviousExpr(first)
+           matchExpr = first + ":" + second
+       will match "1:1", but not "1:2".  Because this matches by
+       expressions, will *not* match the leading "1:1" in "1:10";
+       the expressions are evaluated first, and then compared, so
+       "1" is compared with "10".
+       Do *not* use with packrat parsing enabled.
+    """
+    rep = Forward()
+    e2 = expr.copy()
+    rep << e2
+    def copyTokenToRepeater(s,l,t):
+        matchTokens = _flatten(t.asList())
+        def mustMatchTheseTokens(s,l,t):
+            theseTokens = _flatten(t.asList())
+            if  theseTokens != matchTokens:
+                raise ParseException("",0,"")
+        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    return rep
+
+def _escapeRegexRangeChars(s):
+    #~  escape these chars: ^-]
+    for c in r"\^-]":
+        s = s.replace(c,_bslash+c)
+    s = s.replace("\n",r"\n")
+    s = s.replace("\t",r"\t")
+    return _ustr(s)
+
+def oneOf( strs, caseless=False, useRegex=True ):
+    """Helper to quickly define a set of alternative Literals, and makes sure to do
+       longest-first testing when there is a conflict, regardless of the input order,
+       but returns a MatchFirst for best performance.
+
+       Parameters:
+        - strs - a string of space-delimited literals, or a list of string literals
+        - caseless - (default=False) - treat all literals as caseless
+        - useRegex - (default=True) - as an optimization, will generate a Regex
+          object; otherwise, will generate a MatchFirst object (if caseless=True, or
+          if creating a Regex raises an exception)
+    """
+    if caseless:
+        isequal = ( lambda a,b: a.upper() == b.upper() )
+        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
+        parseElementClass = CaselessLiteral
+    else:
+        isequal = ( lambda a,b: a == b )
+        masks = ( lambda a,b: b.startswith(a) )
+        parseElementClass = Literal
+
+    if isinstance(strs,(list,tuple)):
+        symbols = list(strs[:])
+    elif isinstance(strs,basestring):
+        symbols = strs.split()
+    else:
+        warnings.warn("Invalid argument to oneOf, expected string or list",
+                SyntaxWarning, stacklevel=2)
+
+    i = 0
+    while i < len(symbols)-1:
+        cur = symbols[i]
+        for j,other in enumerate(symbols[i+1:]):
+            if ( isequal(other, cur) ):
+                del symbols[i+j+1]
+                break
+            elif ( masks(cur, other) ):
+                del symbols[i+j+1]
+                symbols.insert(i,other)
+                cur = other
+                break
+        else:
+            i += 1
+
+    if not caseless and useRegex:
+        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
+        try:
+            if len(symbols)==len("".join(symbols)):
+                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
+            else:
+                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
+        except:
+            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
+                    SyntaxWarning, stacklevel=2)
+
+
+    # last resort, just use MatchFirst
+    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
+
+def dictOf( key, value ):
+    """Helper to easily and clearly define a dictionary by specifying the respective patterns
+       for the key and value.  Takes care of defining the Dict, ZeroOrMore, and Group tokens
+       in the proper order.  The key pattern can include delimiting markers or punctuation,
+       as long as they are suppressed, thereby leaving the significant key text.  The value
+       pattern can include named results, so that the Dict results can include named token
+       fields.
+    """
+    return Dict( ZeroOrMore( Group ( key + value ) ) )
+
+def originalTextFor(expr, asString=True):
+    """Helper to return the original, untokenized text for a given expression.  Useful to
+       restore the parsed fields of an HTML start tag into the raw tag text itself, or to
+       revert separate tokens with intervening whitespace back to the original matching
+       input text. Simpler to use than the parse action keepOriginalText, and does not
+       require the inspect module to chase up the call stack.  By default, returns a 
+       string containing the original parsed text.  
+       
+       If the optional asString argument is passed as False, then the return value is a 
+       ParseResults containing any results names that were originally matched, and a 
+       single token containing the original matched text from the input string.  So if 
+       the expression passed to originalTextFor contains expressions with defined
+       results names, you must set asString to False if you want to preserve those
+       results name values."""
+    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
+    matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
+    if asString:
+        extractText = lambda s,l,t: s[t._original_start:t._original_end]
+    else:
+        def extractText(s,l,t):
+            del t[:]
+            t.insert(0, s[t._original_start:t._original_end])
+            del t["_original_start"]
+            del t["_original_end"]
+    matchExpr.setParseAction(extractText)
+    return matchExpr
+    
+# convenience constants for positional expressions
+empty       = Empty().setName("empty")
+lineStart   = LineStart().setName("lineStart")
+lineEnd     = LineEnd().setName("lineEnd")
+stringStart = StringStart().setName("stringStart")
+stringEnd   = StringEnd().setName("stringEnd")
+
+_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
+_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
+_escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
+_escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
+_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
+_charRange = Group(_singleChar + Suppress("-") + _singleChar)
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
+
+_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
+
+def srange(s):
+    r"""Helper to easily define string ranges for use in Word construction.  Borrows
+       syntax from regexp '[]' string range definitions::
+          srange("[0-9]")   -> "0123456789"
+          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
+          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
+       The input string must be enclosed in []'s, and the returned string is the expanded
+       character set joined into a single string.
+       The values enclosed in the []'s may be::
+          a single character
+          an escaped character with a leading backslash (such as \- or \])
+          an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
+          an escaped octal character with a leading '\0' (\041, which is a '!' character)
+          a range of any of the above, separated by a dash ('a-z', etc.)
+          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
+    """
+    try:
+        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
+    except:
+        return ""
+
+def matchOnlyAtCol(n):
+    """Helper method for defining parse actions that require matching at a specific
+       column in the input text.
+    """
+    def verifyCol(strg,locn,toks):
+        if col(locn,strg) != n:
+            raise ParseException(strg,locn,"matched token not at column %d" % n)
+    return verifyCol
+
+def replaceWith(replStr):
+    """Helper method for common parse actions that simply return a literal value.  Especially
+       useful when used with transformString().
+    """
+    def _replFunc(*args):
+        return [replStr]
+    return _replFunc
+
+def removeQuotes(s,l,t):
+    """Helper parse action for removing quotation marks from parsed quoted strings.
+       To use, add this parse action to quoted string using::
+         quotedString.setParseAction( removeQuotes )
+    """
+    return t[0][1:-1]
+
+def upcaseTokens(s,l,t):
+    """Helper parse action to convert tokens to upper case."""
+    return [ tt.upper() for tt in map(_ustr,t) ]
+
+def downcaseTokens(s,l,t):
+    """Helper parse action to convert tokens to lower case."""
+    return [ tt.lower() for tt in map(_ustr,t) ]
+
+def keepOriginalText(s,startLoc,t):
+    """Helper parse action to preserve original parsed text,
+       overriding any nested parse actions."""
+    try:
+        endloc = getTokensEndLoc()
+    except ParseException:
+        raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
+    del t[:]
+    t += ParseResults(s[startLoc:endloc])
+    return t
+
+def getTokensEndLoc():
+    """Method to be called from within a parse action to determine the end
+       location of the parsed tokens."""
+    import inspect
+    fstack = inspect.stack()
+    try:
+        # search up the stack (through intervening argument normalizers) for correct calling routine
+        for f in fstack[2:]:
+            if f[3] == "_parseNoCache":
+                endloc = f[0].f_locals["loc"]
+                return endloc
+        else:
+            raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
+    finally:
+        del fstack
+
+def _makeTags(tagStr, xml):
+    """Internal helper to construct opening and closing tag expressions, given a tag name"""
+    if isinstance(tagStr,basestring):
+        resname = tagStr
+        tagStr = Keyword(tagStr, caseless=not xml)
+    else:
+        resname = tagStr.name
+
+    tagAttrName = Word(alphas,alphanums+"_-:")
+    if (xml):
+        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
+        openTag = Suppress("<") + tagStr + \
+                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    else:
+        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
+        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
+        openTag = Suppress("<") + tagStr + \
+                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
+                Optional( Suppress("=") + tagAttrValue ) ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    closeTag = Combine(_L("</") + tagStr + ">")
+
+    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
+    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
+
+    return openTag, closeTag
+
+def makeHTMLTags(tagStr):
+    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
+    return _makeTags( tagStr, False )
+
+def makeXMLTags(tagStr):
+    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
+    return _makeTags( tagStr, True )
+
+def withAttribute(*args,**attrDict):
+    """Helper to create a validating parse action to be used with start tags created
+       with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag
+       with a required attribute value, to avoid false matches on common tags such as
+       <TD> or <DIV>.
+
+       Call withAttribute with a series of attribute names and values. Specify the list
+       of filter attributes names and values as:
+        - keyword arguments, as in (class="Customer",align="right"), or
+        - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
+       For attribute names with a namespace prefix, you must use the second form.  Attribute
+       names are matched insensitive to upper/lower case.
+
+       To verify that the attribute exists, but without specifying a value, pass
+       withAttribute.ANY_VALUE as the value.
+       """
+    if args:
+        attrs = args[:]
+    else:
+        attrs = attrDict.items()
+    attrs = [(k,v) for k,v in attrs]
+    def pa(s,l,tokens):
+        for attrName,attrValue in attrs:
+            if attrName not in tokens:
+                raise ParseException(s,l,"no matching attribute " + attrName)
+            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
+                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
+                                            (attrName, tokens[attrName], attrValue))
+    return pa
+withAttribute.ANY_VALUE = object()
+
+opAssoc = _Constants()
+opAssoc.LEFT = object()
+opAssoc.RIGHT = object()
+
+def operatorPrecedence( baseExpr, opList ):
+    """Helper method for constructing grammars of expressions made up of
+       operators working in a precedence hierarchy.  Operators may be unary or
+       binary, left- or right-associative.  Parse actions can also be attached
+       to operator expressions.
+
+       Parameters:
+        - baseExpr - expression representing the most basic element for the nested
+        - opList - list of tuples, one for each operator precedence level in the
+          expression grammar; each tuple is of the form
+          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
+           - opExpr is the pyparsing expression for the operator;
+              may also be a string, which will be converted to a Literal;
+              if numTerms is 3, opExpr is a tuple of two expressions, for the
+              two operators separating the 3 terms
+           - numTerms is the number of terms for this operator (must
+              be 1, 2, or 3)
+           - rightLeftAssoc is the indicator whether the operator is
+              right or left associative, using the pyparsing-defined
+              constants opAssoc.RIGHT and opAssoc.LEFT.
+           - parseAction is the parse action to be associated with
+              expressions matching this operator expression (the
+              parse action tuple member may be omitted)
+    """
+    ret = Forward()
+    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
+    for i,operDef in enumerate(opList):
+        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
+        if arity == 3:
+            if opExpr is None or len(opExpr) != 2:
+                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
+            opExpr1, opExpr2 = opExpr
+        thisExpr = Forward()#.setName("expr%d" % i)
+        if rightLeftAssoc == opAssoc.LEFT:
+            if arity == 1:
+                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
+                else:
+                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
+            elif arity == 3:
+                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
+                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        elif rightLeftAssoc == opAssoc.RIGHT:
+            if arity == 1:
+                # try to avoid LR with this extra test
+                if not isinstance(opExpr, Optional):
+                    opExpr = Optional(opExpr)
+                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
+                else:
+                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
+            elif arity == 3:
+                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
+                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        else:
+            raise ValueError("operator must indicate right or left associativity")
+        if pa:
+            matchExpr.setParseAction( pa )
+        thisExpr << ( matchExpr | lastExpr )
+        lastExpr = thisExpr
+    ret << lastExpr
+    return ret
+
+dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
+sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
+quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
+unicodeString = Combine(_L('u') + quotedString.copy())
+
+def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):
+    """Helper method for defining nested lists enclosed in opening and closing
+       delimiters ("(" and ")" are the default).
+
+       Parameters:
+        - opener - opening character for a nested list (default="("); can also be a pyparsing expression
+        - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
+        - content - expression for items within the nested lists (default=None)
+        - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
+
+       If an expression is not provided for the content argument, the nested
+       expression will capture all whitespace-delimited content between delimiters
+       as a list of separate values.
+
+       Use the ignoreExpr argument to define expressions that may contain
+       opening or closing characters that should not be treated as opening
+       or closing characters for nesting, such as quotedString or a comment
+       expression.  Specify multiple expressions using an Or or MatchFirst.
+       The default is quotedString, but if no expressions are to be ignored,
+       then pass None for this argument.
+    """
+    if opener == closer:
+        raise ValueError("opening and closing strings cannot be the same")
+    if content is None:
+        if isinstance(opener,basestring) and isinstance(closer,basestring):
+            if len(opener) == 1 and len(closer)==1:
+                if ignoreExpr is not None:
+                    content = (Combine(OneOrMore(~ignoreExpr +
+                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+                else:
+                    content = (empty+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
+                                ).setParseAction(lambda t:t[0].strip()))
+            else:
+                if ignoreExpr is not None:
+                    content = (Combine(OneOrMore(~ignoreExpr + 
+                                    ~Literal(opener) + ~Literal(closer) +
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+                else:
+                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+        else:
+            raise ValueError("opening and closing arguments must be strings if no content expression is given")
+    ret = Forward()
+    if ignoreExpr is not None:
+        ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
+    else:
+        ret << Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )
+    return ret
+
+def indentedBlock(blockStatementExpr, indentStack, indent=True):
+    """Helper method for defining space-delimited indentation blocks, such as
+       those used to define block statements in Python source code.
+
+       Parameters:
+        - blockStatementExpr - expression defining syntax of statement that
+            is repeated within the indented block
+        - indentStack - list created by caller to manage indentation stack
+            (multiple statementWithIndentedBlock expressions within a single grammar
+            should share a common indentStack)
+        - indent - boolean indicating whether block must be indented beyond the
+            the current level; set to False for block of left-most statements
+            (default=True)
+
+       A valid block must contain at least one blockStatement.
+    """
+    def checkPeerIndent(s,l,t):
+        if l >= len(s): return
+        curCol = col(l,s)
+        if curCol != indentStack[-1]:
+            if curCol > indentStack[-1]:
+                raise ParseFatalException(s,l,"illegal nesting")
+            raise ParseException(s,l,"not a peer entry")
+
+    def checkSubIndent(s,l,t):
+        curCol = col(l,s)
+        if curCol > indentStack[-1]:
+            indentStack.append( curCol )
+        else:
+            raise ParseException(s,l,"not a subentry")
+
+    def checkUnindent(s,l,t):
+        if l >= len(s): return
+        curCol = col(l,s)
+        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
+            raise ParseException(s,l,"not an unindent")
+        indentStack.pop()
+
+    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
+    INDENT = Empty() + Empty().setParseAction(checkSubIndent)
+    PEER   = Empty().setParseAction(checkPeerIndent)
+    UNDENT = Empty().setParseAction(checkUnindent)
+    if indent:
+        smExpr = Group( Optional(NL) +
+            FollowedBy(blockStatementExpr) +
+            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
+    else:
+        smExpr = Group( Optional(NL) +
+            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
+    blockStatementExpr.ignore(_bslash + LineEnd())
+    return smExpr
+
+alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
+punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
+
+anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
+commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
+_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
+replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
+
+# it's easy to get these comment structures wrong - they're very common, so may as well make them available
+cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
+
+htmlComment = Regex(r"<!--[\s\S]*?-->")
+restOfLine = Regex(r".*").leaveWhitespace()
+dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
+cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
+
+javaStyleComment = cppStyleComment
+pythonStyleComment = Regex(r"#.*").setName("Python style comment")
+_noncomma = "".join( [ c for c in printables if c != "," ] )
+_commasepitem = Combine(OneOrMore(Word(_noncomma) +
+                                  Optional( Word(" \t") +
+                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
+commaSeparatedList = delimitedList( Optional( quotedString | _commasepitem, default="") ).setName("commaSeparatedList")
+
+
+if __name__ == "__main__":
+
+    def test( teststring ):
+        try:
+            tokens = simpleSQL.parseString( teststring )
+            tokenlist = tokens.asList()
+            print (teststring + "->"   + str(tokenlist))
+            print ("tokens = "         + str(tokens))
+            print ("tokens.columns = " + str(tokens.columns))
+            print ("tokens.tables = "  + str(tokens.tables))
+            print (tokens.asXML("SQL",True))
+        except ParseBaseException:
+            err = sys.exc_info()[1]
+            print (teststring + "->")
+            print (err.line)
+            print (" "*(err.column-1) + "^")
+            print (err)
+        print()
+
+    selectToken    = CaselessLiteral( "select" )
+    fromToken      = CaselessLiteral( "from" )
+
+    ident          = Word( alphas, alphanums + "_$" )
+    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
+    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
+    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
+    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
+    simpleSQL      = ( selectToken + \
+                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
+                     fromToken + \
+                     tableNameList.setResultsName( "tables" ) )
+
+    test( "SELECT * from XYZZY, ABC" )
+    test( "select * from SYS.XYZZY" )
+    test( "Select A from Sys.dual" )
+    test( "Select AA,BB,CC from Sys.dual" )
+    test( "Select A, B, C from Sys.dual" )
+    test( "Select A, B, C from Sys.dual" )
+    test( "Xelect A, B, C from Sys.dual" )
+    test( "Select A, B, C frox Sys.dual" )
+    test( "Select" )
+    test( "Select ^^^ frox Sys.dual" )
+    test( "Select A, B, C from Sys.dual, Table2   " )
diff --git a/pyparsingClassDiagram.JPG b/pyparsingClassDiagram.JPG
new file mode 100644
index 0000000000000000000000000000000000000000..ef10424899c565f0f4e1067395c6a11a68728abb
GIT binary patch
literal 236402
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%0D%d3SX{yoJ8pY3;j8hQgQuW*?BL=W+fVHSG#4<
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

diff --git a/pyparsingClassDiagram.PNG b/pyparsingClassDiagram.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..f59baaf3929638e74d5f21565f0bf95a1aca14a9
GIT binary patch
literal 141354
zc$}=eWl&t*)Al=fLXZ&L0>Rx~L(pJ@LvRT?xH|+AV1fmA2(E*>ySux)yUVHJzW<M$
zQ+4Y7@a``Zd$z9KtNZF-_W~=(OQIqZAOipZ)UQ%vN&o=7KLCK}@dg$E0KDT~e*yqV
z0bj*LR9uq}mvk(ZO`DmYPwoe}mz5;E>ZC+-!cqVtjU1+lWX?=dvT&c!rj)*B?hjsW
zwx)@R=P06^E|_DLWxp|}!?L|LphL%@*(RY%N>GgXI;PY{MPZD=RE{CXOREs^<-@|n
z>b9T!l+;F&)U#gE){SwGo6m!{%HGea)VP(4@ABL&&(rR)@6iH9#9p@nZ~`6%bQ@!v
zpnXBVVEq99<At4+jEsy-6VZ?KQJ9_>?w{WSI%GqFpqp78D<(Pg05VPM!OquRL9trS
z3GpLV7!1}c;{oM7+r$MURv0Q4FI}2diwvFSvA8%p<EwVW|J>4iX{s{>HMKOiji*Of
zsHSVO_QIKm2rZDBZ_G^TB3s-@y&DbaC^T<s_pnX4Gp<h{0X?m9u#&w@1Dl$c99($P
zsT!s<AUMCYWg=3l!7%1g*8XRa;mwe}G#msU(@!RWo-Ygf|Ikq14ZKLoCn1iN&*3%o
z7v$^!N=f82cIM@R4Sf28f+j(@=B#WG`o~aqgTB5aFKZdgiNvLd=DF#G_<+~fW)z0V
z%33e)C|K~+9EEv-&41l#XH{oXU|D=%$3O!vHbb)5^3^}Mx>VCV5kDk)MKp>vANxN2
z;m!V0#7YjR>UJC!7|;%{_QFC7v{_iIW$M_e=5jx(=~yc*WXexD0dsFKF?vpcwN5*6
zZ*n)=Cc5&Oc!vTe>!N>g37IQeb3Q8$6Ct#6ybitDFSGB4&1I5#%O>#A6ralYu<~c(
z38ogiW=9QgxDw&pDs9rvW%c%B;HBG*8Rqeime@(d1%Fc+f>Ak4;NOF7s_UF_@HfbO
z*5&ZEj2G2X>d}Mi_u(UUtB`=0rbSWH0b=Tj9L`j-9j_l%?Y9J#3Bx>o{(SEcIJ~ZJ
z$S*(F`U`EZ7?XqrhsEC43u&S)X^tg!l5!7^d5^|1F@~}q+aYIc!!fnRR#SFH)XN1$
z!PpU=$62PhxJFYL%|AZcIO$}wcC6yB%i<0Su%N!0k*0_ykUDW>sha=#tsm*3!>mmY
z3B7^P_rRJliZ^~&eZv-%I>F5(RU_%m7BTLWsl+n~A}pL46I1#s-IwkgAIdrrHQBod
z1k_=T{0l4Q%Yg5H3Jc98*pIM}-I=A4=CK1i)nRdsruw~+{qpTh+runSQfcLn^tVII
zUrm3k|3mxQ>G@NWwl&W6n)ALL-dJ!VYAkJ-s#*T}cdCDk&ktT?6k-Vvwbot8aWV^Y
z$9MaR(vkG%Mp@<Ife$@>|9+t^MjN>hH3FZRS5v2#fB)0z#@JLk{NG#AwaHp${>Px*
zSuhvg|7&Lux_vOQA8C;#QDxSD?XsZiZpp{|#|{aFQlwt5S-BVwe%*z^$ZcZy?<@}e
z&n&h#`sacFuOH?}PYl2qi+m4nkS$7@f&CsWP@NB+ETf18lRU!-v>n${;`m0avdFQ;
z-78y^l&l|zofZ0Rg^zn(qDklmvFQolVknw;0{?$}2;u7~WMmmz-Ln7ZhsFB80AECJ
z3THN+@0uDnl^b<0a=+fK=*>($PqoZCh?_h<ZMBZ0$cc#^5JS(@M8jNJX?u1sYI*e9
zj%yitJg-B=9eFmlKg+$ny})<+4c&D^_`*&CsK&)&IF|k0(86r-CEb8FfQl^RDjYgC
zjQ)LRC+ln(4RFMHdF(qq>Sdb8uy_`CQwNMb_n@H?UFgkyZf?q8XIju<EZ~+(bZ4IS
zeYDXis$QCQ_>bHQs|m)hro>AYpFnb1AzWG;GoWV<a6`)sas3<Z#S%mbF)<Eq=o_2i
z!%IB;7+F@2N)W}hnt8d1hheFq?<#x_AG1@IGv_OAyBb(Ab-zJ-Obb>Weo=a-O+xSp
zeUb<Clo!s6ft8-*+taN3L4zzW%Jp0YdtP{nhq8g_@X2PF7tz1{cY5qCp4J^H=r8En
zEsrzVPttGj2_)wapM02)Bx5dGOuY4~KRkRD69c7MXTy<_WuTI-`n;JferfWuY2O0N
zyl7q~+&jcf__i(u=G8hrx8MRkKbO6DJ$8t`6o6nA?DocdJ~lkOI04L*iUAKRBCRB#
z5?=Au5_CmH^}i}>A0A*oi>L4kTaTxYc^}@d+)1VMz7(Nj#|_>ERfC^CSCaaX7CFAD
zwEoqx7K8SK%>ZhTG9xcVz`mgMlBYeN!<R$X7v>jhw8ttF(+ehLp~sQ?(xa%|Bz2D$
zukAP=Br4{aXHd9++hAiIGPYCr^Myub+tNzUJV*|MTmQb<h1?3(o6~B-0>zR(#Kytp
zFC2DU?B)~uyzQ5X^cb`s)1SP;bl<~M85QEE$y1PJQ0}C;W|*+qArGFYtgS!mH5D(+
zEe8HxhrOjv)qgR;1blwJ+4cDLa{p<#?%7lb<z;EBGmzhi8PrvC0~CNc7CY%Cpc%gj
ztvVAvQ1%;SQLID-EP{nTeHE)j7QAl>*KpJs`f1D4*gbB%lGTM}@z#b54zRiHF@t`@
zYpOf;C$>YZg2kIg+dLH{yuyt$A;=8)TYpiL8W6WFtg>#_T9|@)!i|Ufo^VX*1H8fO
zw8Z*nTIw`2(hIA{)2ngBTE6vbO~hkF@Cth#d+~zT-|<<fi+wI=F?i!w$^|l<da<;5
zHqZ9gFv)Sa`07NJC^xcCRkT*hN%U-`GoqKcg@9yOf))r_E9Dd@tLxz)9TDbwoul?e
zArMUvJLbY2Xr`JZG7`D&E|qi<^QVVjWLDn@!*QR<S}N%xC|1;ZKv1NXT7$|fG4xE?
zVRPEA7Y^r!d&p1bz4n(2ctG7;cK6;x_qagB{AY9WPMxzl;TjDg+@CPtJ}MM*4*;kV
zf5Cji?>Vm%H@CU#Mgj;oF!sNJ8yZS$*oa+oSn-+sHl?rfe5vH$lc*vfn@DiRPBmEE
zb!!s*)D_RnR6Pl!Y#0oY2VL)Oa|}d;?Gu2Zt|m1;1R@V&$Ak+(ZRu_{wZ9x`?sK+$
z8+h}x!^TnQUZhW=F*IFtO>pfL=g<RrCe_w;<S2z1(et#f#cJhRf~S$1Xqi3T#IYp#
zVv`V;oW*8C80{Bit@Mhkafoe@<jBp@3)a_Wb#7QRXA<$$YXU91|8iki@@A^n<rpoH
z-tI|!=O-sowfFZ&Uc1O4rfk7f)Z0~uo2$tuE~4syj$gJEJrxzZ*_CBEvWz`LG`T5)
z-L<Gd&jiHD5V>zD-yGKVw^fYvNVKPIXWcz^Dqu)n9q6a{5Xcu0CnlUOuM6Qr#t03;
zh0cQa`=1_ur&dOroH_f$o)z~Kg)!Y4z?G;!HD_AcR3;WEf&^NFffa@PGBIC=0;`1x
z9`L){>m@hXsGetU_divb_;c$l9KZ9EdH?(&*mGe3Fi2u`%vuNEW=t%VY_u~V0dUPX
z%PmjFjc^=r>`fgV)wtZxEUOjh=l=AtZbJ<u7B-rn+qg~DPhy?$O)R4=oX~as?x4`b
z`>g&NZr*i%x2*cskbtMZ>`4f`;RUqrJWmrqz^WtTBeimROZn5C?Q4Rmh)-mQTSxde
zFo4a2l@kW{x32l+$6Z(3XOa;_<oQ2Fp6akwEzD_X?KhHAp{9xy!DJqbDOW>POg+^(
z_=}(Lfoz2S`LNo30m%@Y&^>v^KFrr}l5{Qk_D*Tv7vFH8()QJ?VP(73VycqCFxw7V
z(O-hg&Q<e_i*td_R6=ZV?X#y61DI7*RBvt)jTz=W3_o8D`)DA<k=D-FJgK?S4$PJk
zhT%HJFq?C+s98&F=)t#9zVZ4RQCOmwaC~IxHW6>mtLh}!|7N3<dWj<?NkK--?=&uz
zZ|ksAswX;s!}KycX=zPW@0d-n(1CJMnwUk@5+6q%I!ZD>`)2pc5P@ZSLz^%I8s?tW
zaDZkT2DMrN8-fW=4ZQ5y%F&IzxNeKE&}qR`LtrJ$8J0&z-Y)HRqHE>TZ>@^l*%D%*
zo1Ofs%r0zomvf1<AKH{^4wles6XMVt6~cfF#VUo)URvK<$rgbzXfJuc5&vps(9eG3
z_g8BVFDNJ$IZd8o-t6C)ugO^6cUmzxZ3aHw6Z`)Ja!8x(Ah$V~=ri-1o1cgBX>mz0
z6Z>)TCxpTF?G39RevXinoR9zRd6K(NDobZLu03HJfJ^96(c;Vnv5zsJ^j2I_{d37u
zM0QrdR7+}*XPjHc@vo_-#ASyn^}vp4+gXCt*+nDixI0<xlRm?|eF(otKqh(bjGoHH
zyIwIdu>;+|GJ|6W4wv^tO|Fyx0G{QLIkD{RCwhPNdf1Cl!_#P<m*H>ntT(4P<r&y%
z+y<@6?q0)@CoB+q5Ig1s8MkD?_aR|gb<bm)Os9&nUF?A@V5VKKm13~~$og3=pEkQP
zVPhsO)TVk?FC<@79NBmX6R>Gg(%~_Z^_*-=KQ<7!ud5vwGul$uY~`Y3S@yNb+gVH7
zZ}kJiN=UYqsF;{o;fnr2*z$Z&`lurfhoGhhr1r}Cap|0W!nD8QW50vd*@l+D#Ty$%
zwMwN6Dzw|VzNCq9#g26}8PMSTU}vLnJQ<KW(OuVxb9XJtvM1Ko70B}_v6D%%DAdYr
ze&psvro;_$1Q<n4Q@5aboQKkedL8EqI@$c}@MvFCUj+ct9u}^xZ1Rk2tb{oR0J^+8
zecZ#8vKw3iXE4n+^XXXq-V1lT%?n5ubrv31sbGhkNv%F|6>IN*d>hFEot|1rKitEl
z?)1Vb*T8ArgZsWWA(~bP(`DY7&vNrojdT*&>LzZZPZm0{N?WmejB?q}aUDCxn7^1_
zcdvv`bs_@uo!Fo9MF4Lc!GYpc@y@mM0F+cd*X9*XPYV`1PsOxRD!cda^=O4IJ(<c>
zHGS@t(SK}fRLw`-xp8z?f75)#x#ETR|6pQe6R#x06&6=_6t~-;IFzqfzy&Qw$Cin(
zS*wgg+LVz-HXhsRqPfj=G?NlE7AL?4l>BVl4b@MiZ*Jh%79^Mft+-#7=p_KYWow}e
z&O8J@3ddPo*Me`47?jY?Jh%SnG_6~y$XMibk7kzL2>|vy{H!EeZ*xEkULv+{+w~@A
zGuRfD2(hLG3F6K!TBG9VLn91&bZ5~MqSOBIs&hA+UBel1(J)$*w|cIGF+jQo*-++>
zp-)Aee9#1dk005TIU2q=C=8OBzNcWu$5B6p@m0zqWg>m_GVfiJ9)iO2-cZzoPG(wn
z%qXmm+>C`}jPA)b7cma{dJbE!9Fb*HaBED?vWukXMEWSn=)<=Fa5(`ZXO_r`(aeT|
z8Q*utH=Thlpa#LLZwE5T87_q~dmn`5J&ghhTJsM0B_I8Lf;mgJPrl%H#v5cFS5qCy
z-sN%w*EffFqq)t!pyP&|_Mio-9L#Q%HJ;4ep-!{c@~$3%c{mcRNmpr&BqXfaBd?nV
z&Jgd%?8{eC;h>$IaST2gy=%6aC$TE#Xy18W{7qMN8grYW9-xK6tUBFPd;HO-95RYm
z_npCg%1*~?RiXL$X*eS;WFbSHitMaK^VR(u6y~mF^Y#Ft>B_J|?Z%m_r!y;0-W6TM
z$%9r+;_nzX8M_I_ssU%pKz1x^AbY(J)=4vD(=C8J@<J!MNX_BL`F>P*4_xz!O}^XT
zwY;Z|OH5;KO$({59*~F2?iKHS&ca(e;#rG9D*ZjFbiU?oo`B3@2%1-zZkn>?5fIO$
zY<nsTCDI@hb|akAIlye`yJ2^~dU|YWs?Z#mTBtStq`)IxsIwN`nI8}@>|WKw2afLU
z4q$W=?2k#)M*<ji5HbRrLsLg*8ORrII*D|zju<8?_-2wMS~cqME!+x#p{Tw$seR|D
z95$59Ru`GwrVDf%O0*7JR(TbNqF21^A*d&k#UYaGJ}p~)dStmg^|y{>7#L&or8DK3
z`Ls$SZyldX{KFOqeC)Wb1#MgN)%3qieA<(8J|V=$+L%}0w{_79PO?t9kw~q&NL^7h
zW3d)|U&pq4XITw4A(SHrbSRqhVYwgvc9K0$iOk8Xpq5J)-s)qKU;RA`pR0+v(86(%
zQytP<su<8tTycV8B~>4TrhgoA_c46B%hvn6DuBBkbxha_5s>E<MNoJGcDrl^4#EB&
zhVi{yOg*i;RVzuBN#S<u=N4S!uBbKR!>y(>0#$}zpHn#b<hNZk+fR57C*o;wsmt!P
z=gi@J7MqJqvD!FE5sHnoM_5kWP=Cl!ukmD=R@5nN?ekks+=xn(Lfv+3lhTdS(D9AH
zIRnYuo8)&?FTTh%#MAR1+}vR6*2kA7GYpyT8@LQ@@^g1C@&aQ&8+A|WA&(KLcyFK8
z){5F70EleEq$N>&ne!vog1!r9&+O#+2)L0uN?ho1JWa26;60IDFDG2+l<`R7KWq-|
zz0dIX^klEZouyw=DM=Q%vr7bLoIr;7G^NMcU8Q|a*`0{s5MxfQn+b_ek2JAxcQi69
za%Bz9Hi;O7P-dJ9Il1JsZkja@X{Nbhcx=y&TG8=v+?L0fl{8ImL&dl)P7;!qJ5xTv
z0^Y3IYP^Rg2jdY%MSm7Dn%UKs?z%lw#VImWCEou`(0fkxbh5JtkUCIp`_e~x-DPvp
z%QM(Y%zZogahLu{XOo<<dKJvO<Dnd9rHA9p5x<kz!ni#d9Fl;y=Y3W0sio#!%%Wao
z#xVB*{u4)2VsnouAy`PVWv#*&oBT~XpBtZD+a+o$LgNPsv4iNtq8acNUzzR>5ez_9
zr+Vt3(>-N~kXM!AN?J|yF1wmQD@opQpu>90eV}wZ1Rx=RNs?^l4pQHVv)_!=vrtZ&
zYm7??3(HjxP9|@a3f_(7Bu94#Sz2*MFnI&okOXsT27M159X~HK*Khr;p<>HFv}_=n
z+^?chCa)<cTg4AsNsWl@y?qOlx76evngSk<KPvGJ3NllL=7@xTiNeXT4}3>_Wz7<a
ziA}&!51ecKd=CkG?Zn+CqMv&8qsnXX5%s2ryL-w3a?P*+U<nS`VqU>9caU;B2Myux
zhzdVBr#_ACp5aZ%q?h4Dw4Mb&$aYX_iCyU?K3%<U=uwH;TV2OD5;HX7kaD+bnU+vF
zQ5EG1PpH)DPQNIh0_U#OqlHh$MVN@uVpw@w3AT0g^LtmJw;dqBpqw+|;FCGX5Zr`g
zZ1Gp$Wv(MVqV}8gJmx#lHd{xa4<XEIi*V(E%M`+VN6riOdkhSSJLpu9l`Nx<{ylIc
z$ib73wPfDdYyyl1_`F7`PsY+*$e><#^>u2rb{hNh!BS~-IzWXMJnCU=8b0ImMun44
z=xxZ&)tpm`MQ%YiZS=Eix<ez}74d%WGG_J^!U(nEnY_q%9d4F!dulx4Bp)_?dS$&R
z&bWjTd3gg&{eF6Y@8TECZkU(v`s&^|4}WIg1+zM-Nw1WrJZoC}<xc2Fti~w?Fsc$-
zydXo#q2P39P*5dpiEI9^B1V8d8<ulkOfm*A?K*}b@ONKf^Czbf?MHyi$5sW6sl4e<
zldNMxL#BY1<GgaolFOuGT|7jtt&L&0t8dK)HN$sK<BkY-0a7Y|0>2N16q2r-+OlP{
z@L*h;>JAvnq5?*!P3iSwlFd+Dll6oxJ$sVvW*K}CplWI;u@L-gG1exn@{rdwO#4sT
z+oSupTMxq(5BcA2_Y_<!+@=HGv5hf=kRYp54Uus-T+_aY5S2K~H?HW1EZ@ypfj#Hy
z+(&-y$dLz`nMZRi(xf!SWazu#htXpfe9^)_CF<#%cp7$3dDCiH2<z(?P5%u|6~B%W
z>TF<qA&>=aO;jh2t>2lqBR^!WXFrv0vt2w3djK6(8tCSKcNX?ndG9fX@6wbT6p`Dj
zh?|SPD11+*dyu95qfiSAu<Y*{4gaj26Md7!Hyhkpm@pk#gQrX#I}9*OeN-%MI5gN%
zSnAR~GRPb%e|R+#F3{<r*j<9{Q_N|d`lK-DN`p5I6RVcpxo_!-hyKCQrtG0<O*VS*
zEj&Z<z*YMxFD9UF&gtoo6E<U@+0eKUe}rM|KA>YtkQ3r?uy)w_Ij*+Do&LV(sdyIu
z@?8W+k^A7iJ}9h*%`3-qZ6g=2aokv-94~^oKuSfX_H-+YiF%Y$mmyjxWyHeOc^z3Z
z$&@<rf}iAR^%@4?8Fduy{S<)@*fhDKAN+Cw1b80XFvi*-tR*lA%iQu+oXQ4Bc-&Gk
z#@aCUV_&@+p7ZMGZ5uf*Yq!0vNtw#8c|L>Rg(jJl96*ZVJf*K40KA$ezM8k-pl#Zl
zc)^vZp+3rB>)V0U-!6mnEUaS$Wh<Nncb`vp8=B<QD_g`H{}_l)*y%NBe(+BP$?!ct
zie=IXS6ok&PSy8uAc0sg{hQ0t1mQjbnt$Ntd33$GU0kWQ@et(=@HSjPA7TTzx;*m{
zEr%Su9460VqMh9J;@yxWZ<;=oiktfo0%NXQ3yV)vZEr*68}UwIT(`8V(FG-%CP)8l
zAM~Bqc05?f%o3n!QCBa855`ZLv|fJaerG6FDSKY9fV(ka;h;8ON|WYDKCgfX+`Hm+
z_X^YXv3URazvQfoR?Gp!g`F#D<F<BzPIu2jRT9mScp93_bm+hgb^l;GE2Y`)oc}MS
z{2shUyPnz4Vzd82iO^KTBPWk#w&3uqG$CpEZ1VK9vZ4AHoMcb>fnO9htJ>FG9X2f1
zyZ`|RufqfJm_;cLJ1ZW&p7;n*=qIB4b9S}}dg~3vrq!cbzFh)=Xn6M*KtatO%&V?(
z1inB1hGa;7+x=`VoF%kkCUjXa{*nJm0x*hur0w^2C}yqq;&*q3I!WkLvZJ20vv`^!
z1sPdJXyJ-xa^^E<{jDbCA_(RO6Owg6j%fOx;*1O0*2!2+^@8Yx>8jVEI}x&6U=hNP
zR_w7dCl$sVD<_&e@OY7c-E3CN9LU9zph`CI%LKRL#82U$UnbI%7Cc&z&A1UQQlwpX
zpXhwgfi|g&Cj?KGo-9m_x0G~>`0PW3^<e)q87V6Po`v}d@tE4Bw^p#~iS8?^-DRs4
zKb;e6CXc2b5who6WoyP?GL-3E-wxcN#QszrY$mKEDC(0%>3)n&VMbhx3gy>hrN^z_
zE99R_)Ht6>2)#=^O+D=_8M}yLc8Bch5zY80dB>Kt%zmr9)N_bMVzB0XI1g=_{dTFe
z*p#+}Gjk=XmSZ3$CKi2)mwp}@zn14vD4LczvxBAeFr|i6O#l;3QgXDEKC`o%WZiM|
z1ksY~vOu13JUDYDoo8^H?SzhiqvjOX189Y7a2#*p9V$SdW-+xi`u234R?#@Mrt$v!
z;|C?ek@{;#MM^2ljfdxHv@O_vMiOd{$;NE!l5J+1Aw-k<m}gwU;Bdw*aAEw8_2{`~
zQUad7&?R$d=*!`w6a<7%xNPQ@G2Ka4@-u((rcGA(&=Tx1Iof!~l}Z<SV<3}=1iN#V
zs!;$o8Q>NIZ1=}f`(VJwk=7RF@tKA#MJBzB@BT7Mlc^(=n}yN<0DN(foNYmN<P-P?
zMKXI&VYlqvOmq7*98z-T7<XG1`CMw8L9$E_FJ~A!a}`P^?<7QOK;-03YC9_D%&<t1
zlY-Nx?e9*7rH%1D!cdoCD0|Hc1|*r&<+s;QH-~W%=4}U$_MP>Y#{kKVd-|RB60;ia
zZ4WXZjx>*sB97}p=Gr&{ficVixgCL=-qPux_~bPqeKTM);<xTv$1gd8F9UNeG{l$F
zL@fjlq-y&+={tm<+e>{RkcKA5Eb+&AGRD5WU*(&e;9v}13~{{cDMQJ!=C`dsqDbJp
z8;R>UUsWG~$BkU2`G!V*?}~RH62<*x`d0BC(#2c$4k<ZvJfinjlETBVhaKPVt5wn6
z%i05^D{yVzx=Ny5W(bjEN3hhZl2+1325id=yJ1eK)tE4y`l(=y8F`{)_?w5u+<p|b
z@bJA_KeL%P+hfL$w&{+I=`4San61Z8PS|r#VP@HoHswQbQ2Af4-%q6;*CA%C;^Cl?
z^~LMIHQg}k6c0*5h)r+Osn7_^924TZ<Jy8^hunF(y!{&%=)$zrO9L`hva`q$vyvUt
z)~3rx`#W($a%W5aR=NEa#2B+bld<9})1{t1u+$YM<v*Ab=92{I&+3r7X{{Ic4&TQb
z06vduZ4il^iiGbmvI92N)Zhg=&Wyq<XB+1pO((LxJ}GI1Lgc9Hw+w3RbrM*uDtN<4
zTJmDo@&~GC&p8Q@nmDVg6Mr(=I|?*uW-U^ZX@XEBldEQ;xr@+*!kULT7a+!p-X>)e
zESh$p>pd~DjJi`9EAf<mcBb-TOx4h^xdAzmk}LVSc*pwB`3iFZ_p;ac`S2FqQ%h)<
zPV(MlPBoGxjW=y`EunuaJAHi2)aT3vUI+qKX#BAcnLKW5Frs6{B$&-lXuhVN?M;!L
z72IFMqIdJzV_c^GV%wWEUidZ87AXxCi4%%s{0mGvheEMPKDPbLIy_L3Sl2JD6(A!o
zmiTE`kWiRm@X0QlrDZa9lGXZNpW*O7y#R{jjOz&6hpB!3hn9qI)YO-O=8bPZC&=*W
z_~s8(zk_SrH<EK+5IYr9?jH{dDlfYUsjMX7ONv?B#ZAw2Xcp%n8SD%)6Q%iA5uV*q
z&@IyjIl81DeQ8eAj~^H`rOy2mULbMxu4_MLd}UJ3lNK&j-e25L5Bab^ZD8Y9{z<@=
zY6FTD-xv&lrV$>H$JU70`lvfMw{b-Rs~Q>xgx&D+a@NV6&o8i}o0s*N4FXSw*#)=9
zmiIS?gmS~=G{ORU895AypdO47T0S(l?C(h<xsB<d4p<UT*~lX>XJ&*UMel3qCjeY7
zDH4j6sHnj+@tl>Or8oob0s^CyX@(GdccQ#{2UwD*wyetVY1Q+=l#2s}&7V}scOiBH
zpT!MSjoM|5y=e>2<N`Ls@KR+q^qmJt$;dLWK-Yq-D_P>MRHl|>4b)!J1KVk_<P=Z{
z>gSHvL|O~K^>|+-%kd7*zF*-j_51*w-)SBHP>{WY<?^lQqiMn~vrJm6_zrwLx2fXa
z>111!c@w*F^$%+b%aQZw9v-v+l>{n?VUv83Fvylh9l2BU5@FwY2eviG6W&_|@dAiw
zX?!+vXnd8b(RR${IPYZGB;Uwl(Y|{z%Xk$7*-&?RDxPOZeWuV?Us?U#$cuAvX`#3o
zD_>L+kz=@FdK`}>8ylLY%h-R6%>xaHmXOpG8t#>bFm)2E0pM+rgI`)AV|uv2oy1Dk
zR=E2}oq8-e!wNSJy>=>hXn)#bnwH|0xht&$HK6t1qL4h^J_-L1(T`Udi;r#(<db#F
zHY`*wu}L~d3*LkYW*OgVTdclh;*SMncsZ}Hk9$tDt`)V{C8tP<y{l#&mJj*37`F%C
z(uzH%N|W+!(xn(yy>mTBtAB*r=4W&pQi&secxM^~YoG%HE?yR&(_fiJ4H~a{3Tm^g
zBKgd|@s!N?u0w$D=eSy<Nud(FR|VK$O8xBkG*%+achf)I{q<Yjd-dDMq!y<KQf^@<
zS09#qTptTHp?jh`rHcDH)3wymM@&H4gI4gCmWV4A^YBb^R2Q<^5GG*tp*!Od&^u&4
zpxye4QPtIUAGYtSmz*L9g>H7r%9Ehr-b1_0bHtJ9(c53q0jG*;+rh`W%#-O2oV|sm
zSS7$aU(UrdZ}_7ZEj?5(lFJ!D#bWP(x|kS9@o(Xt=26~#+3MK(%ligc0HWYb<a|up
zx15b7<y_rhWrp@ce_RN^P{4-ter|<%l~z<j{KylW=6R^=R_3rz0azOOqK@%;Uk^x=
z&4PsX>$PmO-sOw_C+(=?6~s2~aHZ0XoV&fsNXu^e9f7;<U+_CkroRO!&GzRGEnMF=
z+srExqiJ=ltvCzSrwN^m>lZCP?%u-#R$7ItRhx@+ue^+o<^(XR13IR`^`_Ip&v5*D
zT(GSp)&oW8G!pHLb^Jud9QDFBE7uF9Y?IXw71v}L@U$a*I6=9lSra|$dPoC>*0>Hk
z*D4ekR+c~LGlV2dM#c`%T@ZZRl-;kwa}lff7p+tYDwjib*s-Q@Z~-n_UGzE-@KO{a
ziZ(`9M}|<Y6N?>DsM~`_i_%NA4bS~A$4Or(Ouf+x2BLN&w&{c94@iAK$GK`?ZQ#Jd
z*Q3!JRad8eXn>6%-Jk##uu4^C^Kk-NClY6=mU6nf^2ez5q}Q>`$p&rdtuM4rB&JiD
z+M{DEhKr3yFH#2X^Nl5=K+`#u^F>{<hq=OB0YneSZ`%cxje5sY#orD*|HcPgiu1#?
za$f@<K3y4zU!<#(g#H4k*vQ;OZxE@TDB5S)&Jw77ROV>jn|IcGukCjlCvid~$&T|s
zxomK=&);H&yQs1?uMtV+jWJ<Qz^Rgd4^*)8>7@t`S~0_&3c9UXJq9Oob2YniTwfFs
zgM)(1-gd>LN~|1N@lEZw%4MT$-4Bmtt6t+>3ONg+{mK!Y_N!g+2&W6LTC(^@rlu$H
z%(~;gam+?@1vLnAcp=(t{DXHtQHDUmrW<_M@;IzWmLmQLNBg*6Y<kb^=5CFNd?+-i
zk~b#1^v3?YDy@9d&>xTE8T&qK-}*p=vs$W>)?cg(7&@Z=HJ*m@md7GF-yvK3Yy6kH
ztt^sn7i!-xY%+4*`n>s-Bg$Q48pL9donHZZIobLR_u@S1YhQR#wqw0rUAbS>CM)~g
zXP{26xptbm!0&ULi2`uNI)`Zm&Jb6i=ri2o_FVO5hRo<4GH7NIF`#Z)u~t#35!V%L
z%VSoEKPVY51s@!rQ7=qRz5|3XXPPeNJ~E)c@$sxP-Vp>HT85_~x$A!C4Ype-oJz5f
zV<4(FxsfJ>_MPCr&@6jteFdUOQtVBz|2JcuIac&;tab_1P0O^YhuGbG-X!eYnxZBN
zN7Cm><Xim#>CUqATv@4~%JS^e&|7poIIE3>i%C;VlSf(V6k$EH<1zjN|F0rO12mu5
z94RpUT|6(7$op~DLtQx4DH_UU{N9R0s~?kk99iho@MK-3DKOgL`;gYyP|x#x4QfSb
z)R1%(YJH-0N{M0*?+Zy{J|9FE#Dw{-ZsBF_PVw*-^&(xJ_$W$fgWl=3jbah=XPSQa
z;>EN6xaZ!$t2#abA9ch!Y~OkWzof>O*|Sg9E3ZVQxUR#6{BlzGXh;+;p49yC58Jh;
z*hng_H{ECd^I-ds+~+wwf4<2aQGxk#p4H_(oIJ(Q9dNV3H~cJ14jna!pP_c}r1x?4
zzQd)QZ2@J`lX*Q}nDj*YsF8Y+QL<J<u>bM}KQihMdc%2`jqWz6xV9Lh;vkL;!?Ug7
z+`DU)(u`r;n1+j(G#<T3nC3%vNxqTzh;^Boc5r)!Nr{x!r9C&8YOrZZm7=#Hd+a{!
z<H^o9JanXnJ75UvPkcy?Z*IGgXh*o%F2x5B2zU^Dux_+xYTO|Lv^p@2UoR4xTm=fQ
zIh5se2XG6F>3$qcJCg%ixNIb)o+g3gbS+LbFf%z*-X&EA{(j}X-W01h9pI;-ouV`P
zMB~_i8^Hv=4`Z-qM0q^pWZqU0m1y!P?w~Nequ^)OC+hf(zF~LZw;Fr1X9h;flCO6k
zHAffhU$~F%^oG|urp?V6B%P~6TjFm0h%ko2*Ycpawg(x&<91OtP?o8&0>9eY7Y-x*
z=REGZP5ItG4W_k^FnzLRjAT}5K031n0m^_qe)wrppxsta^K5y9uSe^qWiIo%kvp24
zB#fPz=|_wKF13QuH?|wT6&(guT$i$4^+joNvK|ULOb{kqZX~5Qect{6Y^l0sk$CyT
z7x5j4CKO!v$DNX`3s*8zwcn8(v?xtdD`7O`b5&S@TaOm5)gmP*#yWaM60YMDG^DKS
zb-wE3`0d8TZjlUv2D-xXAj=r61eVPRxOm$QabgA&yOntNxJ{py4|hsvTDD;lPa(+o
z#0#;rYEp7_(_TB+)u<BH47Y5S=SABmJ9d_4QMXJapJF{=S2_dBsL3?Z_GhBH+*2Ij
z0e;H_T3Vs@l;>ybn_Pg?zm#{<i7*w(>bxYvY$vXlzlZ2$tT?N=Qg&mN-TUMvdnO9S
zhcVzuF5{Qk;67U$i?>Fdif?bC%MJ`z4~U5299)6m*~iK1jREoXmNIX^K{Rk37^X*@
zTU&Yl;hD?|7*_hP%2k0qVZvT7SBH9fMoM|kk@vs(YK^#@e!sTTO~_{L&-5Rp?=Mq-
zc}di<jTLUPc%?+)<a<c$9|vX{yH>-b=`wzpQpw$wPmmd$!ejpj#PX@3c+Dcox<h`<
zCxlsGj+z#vL=X(pHVw)-FT|pECrY1seh8R}#zS_F6D0Z#gq4}cObg_Q!xws7cmsHO
zO4n&AWWsYkQ4f^U8UB@u+!Hb>Xe0?F2{PlH_b`dU>I47+GW8g4hiEdKz7I7~ONeoh
zAgu4<+gSst<>9*@?hotbufkPBm1p7O&yfM7HKRZ60B%!EqDk^9!_<t8S=B1S>y}LH
zX(`EH%)4QfS5Re$FaA;Q3|YboEiD&x1(TVs1<?#L^dEltu$9saA0V;G{4d%HTg`U$
zYhrTikZwRV=Q+zF$e5LkEQ8lTE+j}QsSk=(V@pl4tcM=u+$v-sVpfXG*9hJ!-hTo&
zZ?R~SV5)i+qr>^pCr#f3E<HTxgAR@ZHT?$OgEL;~suG;15U<u<!KRo|>&D}~!3Mv{
zU(%IPjQsR$CTe?7XGbC)2F4gs8I-htHSY*z2qRL#3d$9>n?4Y`3a_p{zLul4a*kW8
zRobSjRD~IV`D>A(4v|xxGnL-q`g<LpJyra>n(T}Y0L7+&3lC#c;^p?=mrdusx$41|
zcojQFyON~1zCLVf8?f(P3M9V((D?)RnYQWpr-iY=yvDpw`}UK6f`Wo*JOub7f~KjD
zDlob8D24eW%wjaqO{o#<JBg>Y#)OYuLM@2&QmeAYgqrd19Y0bVcZTs1L8)b=lK=rV
zH(Ip?NpCSH=v=!Zxi+sF-4TrYF8hwb;o~Pp*H-2ATRU?EV9L%Mm_Epq`U8d)d|l7s
z-A8le4!vuYypvLlvHdD2VpKbMMT~4dDj=>h=9jSgW(P+`vr>_fDugcB=(IkrGTD^E
zN7)?z6WosrMX?6R^BT}nT?AK(M$7mohT=kE0I6g+$~Q-Lr5hzwxym(h;fA8gDp>W-
z98m34%f>b;Q4w!=uX;dKqA@SQarJ(tKUSxO^jGYpSKYPonBT5YB}u|<K5qcCS~yK~
za5o#HA;(Z<xB6RS(eWMNx<PvZvaemHDrRALHg+5;PYgcd0RTb6Z5KhRSW!F3j^LL<
z+@~7rPj&lv3$uIdQis^wU9RIeO<w%t2X<xT#+%VGi1lc=S`RVCCRYo&SHBbRFe13N
zvBfIcph!dQYUinVj2Y#PBd;wx2jr2mIiFtPnadW`Ab2T$w@N#9#p5{X`<e88?fB*_
zA3-7);Egth)=6v{EkKAr?}dTwyoXy95xzL+>kz|o&zJ~Xrz*6ry%MS=%t#`z6$B#b
zGd!;TsN&zbO6zs7G>X5fHj(GW=SbyF8Of8~ZJYBd-ghg%E408I@zs&2LB89we9{zE
zvV0S=!LE@bYWjYcZ}C!fb$6jgc?VYEAUPH#g6qtQ&)5h~y)!3E_e?oU!Tr<dmJ|`M
zlk<VA@<~HxI`nnG{0bhP)h~jh_g%S|&@M5xsM=giQR%vF+sV4A^pUXxhu@GVi$XZ9
zP(Xk9%=Pi;fy1R-&Dz8BG=yqvqVIk^M=QJs?(^kdXA<>IgM=_65=UYedL-)5^}iY<
zzwthc?cql+ZgQqN7D4*G<k|6p^q22EWM3tbcQ`!!!Wp+-iJl1)VBsCAoz*%mVc`<J
zV7B^xZ~n$@b4!(|mHp(i-L|56%0Iojl?4c|aP7qX2-s-KLnjybC0wWW8oT-<&ni)9
zBX;cN)#f?-3l|g-`?6MjTO@@6tk9bG{M}(Uld&k#reCyM=FfW+*cB|HAgpP=q0~_{
z>r_x6B0RD#e2%6*ayA=E{n4%c?u7FIC!3_F_UiNZOp_D&187%nhNFb0SWTmt5mFQ5
zIF{csL76V@Q_uDl^Z4r9j^9^|9U9|Xy^%BMP*fy0H1EnqVAnrfeH)&OVZ{;PRi$u1
zCzrXvN^oQIyG<ENz*{=%H&()8Ng@tc3b$~*!kVwF*J(UP7CS}Gq+9=tGkCxEUpvy&
z2!?j_pexaHL94SmI%h|iJ?h;8K}r4oK}gLG6grCP(F6r+c^6B|hFj98*4`G1+tNc-
zh@7V3ow4(}M#Yxb+7)qZ;@gagRzw{bwB?Fp$Nmt_h>7|h<wLNU*SJuZ_pA>4oqRoz
zjybc}{9ME)6t1{;r!l&Oo%xF^xI-eOGDuG=E1RcX=w7irn~zctDm`58HI@y-We$d+
zSS=-~gZ7%R@3+-EV40qXKv!xIjlY?l$$q&UEmNIV^t$Y*mJz7%E5rA`VJXypUf5RV
zs;Sv|#|$m`x?ijQA1Ac7FEMk8EoO<;H~Kk@O#04H8bA~_!F=}L%gm=^>YeBIc3s`8
zdU;|0L2Y1<c#Yj))f&HLf+~;o+x!LV3yVf#pcrU)NzH4x?PB3wLO^!!v#pP&dOR3o
zEMPTm-qEn>xN>pEd<J~w;2t#0th1Z{8jZ)bc7t`99KJ5GM{axwK=f-Z^$<Q}SGozA
zTtW|wq`gY8FwH`YnslE2>v-~!{jwSbZiL#vRgQRjZz`jg{inD~zqTQh-*UyiLYNF@
zlk{>1%CGd+>|kh^2g@lxPa2R94T3wUwoK-U`KcL|ZbH8I?7b^>8If9g%1Qt6*LfqW
zDk<r(nvo=gGX_92t8;B@MqynYdEGglTsL^Swju$zJwZRZ*KztW-ArlIKrHA*n!#yv
zk}&FMrkfT^rJ3gXTM)zQ&1-m0eGShpF|<0;4602QUft2^06^U@st~y6K3_<YNS)DZ
zOoml3c9q*(o-qyg?kX&>>kn@&ew0Gd62g;l4`KNqW!LPuHBP|xP5<!6l9%^+7LJ~g
zY?hS?*QIs?UytL%3%Yx8(`uqsw~Z|uY2A(-l<#AYE@$j91yT@$;aj51ZL-Vqr>sT_
z{}a14O`)CmL+#&bJb8G3jce<7P6V#saLi+E67mH|%*)6CdPUER%MoR}>(x1_nx8l=
zgHZBB+_Wqu`Vn%N7MLjh7c@IB^`>3e%Iai~>rMa;y9&((4wg8?B%2*Jt#)>FyUfF6
z9TR$o$P?GaI4^*Mf~J{F48<xV{;6=PM#7$nrO4&KOR!QkmpmpZm;nQPp;gJpsIlW*
zVLJ(HnAZ@0hj))LI^2m24fJd}=@4Ysu>M}gxo<5kK;lkq&CpH*U}yOGrA34*=Y4L0
zL{F%cOsFdxM3B=J;tVXonPZt&46U6f^{wp?_<(a;>X3JA$n>|&=1lpfP&s$SnT#xh
zGuV{+!`OY6m-BjKC$V|0Mh`mE6uv*bRa0^BbO@@4^ZIHG(+0*6ISHbcgFx&ayXJ|B
zacxYO_7A2r!}Q7wW-rv#4?W>B^8>@S^hdf~E;A&LhrS18*Kghhu@nmG4HIwwC%6w4
ze-==5=_$rMaLU*)xb!MO=o2&<xnXF}tx-!@WA>oKG4=`KLKb<CV-znkQsr3FKa%z2
z;S->Bkpz<KrFs?_F{QSVXXZeih#X2SxgyTt)u)mW<0xD-B3|mh^A5gdEN|Suj(I7X
zGo-iDKv=OL*SvsL7rPQ|4QzlNL&x9Qy~;&|Aswash|~2G@n4)mR>g{_<)DdF<!;=F
zy~|e=GBNKi9rChi`>5@k%bBjee~9rfpQ(u?Kq?MeH&9HQ;B&3vd^YN*HIgvoUyQN;
z6W$HUI>x`Dvkv9)Vaat;aJVo!3)cA&(vXW`5Fn^Gi#9Re`P!ywW^5*ahqG%@ug1?u
zj4T)U3N{!%b`C+C5sB-;{?hialYF_*8Xc~C3-aH`iGPEd<lljGu8&S$J5smryroM}
zYF?{p#HezCUnX!oV@H{|aD7MgzwT1<Rns+n$<!i_P*AN&lwdq797VpGcJ?s4M`;Y#
z2^US@`%^{whtGteTKF$FD_5u%ZN>Kr^{upJ0dN#|?nv~C)zti>in%j0WxJ&}@x`)%
zX7E3&S0Dt>ij5D|=NidtL7Seq)P++$bNz)tp^xYQ-+R07qHEWk&Ht-?3!hh~BwFj0
z2?)1nTi@|`<v}@s$C3q|8XZ@cT+O5cIT{aS>-7m+)yRF%H>#TWFYk%GCagkPjmq%D
z<}r;XYGVvU*-o$lq%6-GMi<K23r*2)*e}Pq;)rvqf?n6qj1?#<gn%Ll`j)2GbF_Av
zB6`*ucgWvHR<~l8y_K&TuJC#Ogje%1=#kN9G%CL!YVp8V88Z7bM|3>mr-F?*PIeKQ
za$Z2@xFgNw>@SesCu3P?#*X?mjPXh>;9L0|z33WR=+KM&Tw*1E)TefY{>F|<9O#-E
zO?MHSP>qt{M`dz37;?r8EyQ*2(c@V%Iha2wSA1nh_ACv$@%5I$^0{M!%vIw4=3q}*
z+1SSCpK1xYQXGfH30Hu~PPx&!$eg6itg&SB3j)gO?&vK{#&lUEC%iDel_N&AWrTvZ
zp}kQ#B9(qpB)f~jWsatMNLOG(X$g+SP?otPzr@Z%i}`EjXH0~yRLBR7&$K`x*Z}g#
zCyy#aOs@g@{nqQT9HJ&6$&*<=cN1omJyBJ?U-Je_XEu@p%H1495oCmsL|XfdN8id<
z3Y$zLxmQk|8H>91oT=pS9JorL1D!jI33U;_pGq4{&Qq{?RLOQBcUsG#IUgV%`10N1
zACc4MsYFX6aK?UAA3JX?Xm?mInP2wQptysGZ1Y!c6YDJ-01tacZUiLHiNOrRCBS&@
z=LNt;WNG%8>Y!8fE*F#SU8QCbSotvOdAW)vcb1tcTbF{Eb?_nU;k%1gmmNKbr||uM
z1@<Nbm(WeCuMBm)!#~MF^ehU?s`kWc1P;TPSt&UuG8FBkkFh;Rjob%NdgUdNHlH%I
zhI3|4XV3|WkH&x$aa<vsh{Mv#WeP9?!~}2XY8=9yl7(WC{uALp%rLO2|DzUYzKesb
zk8w;Fwn%*!`+xhI@(2}2#2yyt2G?XKHehf|jcQ>&2+|oydgKpCu4jn_TgyG}oYW@H
zw)I5ZGz6KA?Wyqr$TGH8<K}<!#a#R})}bySAf8h(y62-7j;LRNnftcFwz$;X_u4xp
zM%%897OMj5l{23Z_F-<$dC%~sOyJgE*?X`3o4=7nzv{LXK9l(h{3WlWSAX8NH$*d5
z&qC(-*H=7mxYot*HCOrBgd>(s^0J7|Tht5?(iPvYq#x)2711+f(}gccfBS_dR1B@l
z7pVNG6QxP7BoezuRJSALarO7hkJ>+%)}KE^Q*qhA^ZWzAGMum9k}>)Vm*2SAQb|@5
zc{buLG|;F%xeXv05!bz8>W_t0y-pAaT`EOE$ngJuD=rzw%<r)=e<9|r=~*a@3J1Uo
z^Tyz-585~qB+vFJjx>XV3TVPFKV01<k}oE}su3qVNv}0D1<fP2$~`e8z~9rz@$OTC
z*M#-|)mAkol2iIs&XsMDGh%!od^4FYNf+Ut`c|mZC9t4`kR}}#AU&Ub><sWdEGmg0
z;_j?f?MW2>FFx?v!zGK~(y26+bl#SHS?$RZdkL?<++O3D)rBK4rjk)dcx30lI4kJk
zdluDw@)iSQECc$)(P}FxNZw`jfIoqoI>xB|g>vjl#rK9vjg9++N}PVn1U+ynSZbV9
z%`n)VMX~|Wx*dJIs%lNA)5R0lv5&JJhT<s!-n6(%jv6(`BX?)`W5ti!t37j~AxRt`
zW`lCkyG~#LslaQ4;S+Pl?%3GMmt#<h!}pwgF%Y+*|E&ugriidK@_L8-2k!jyLTWNH
zO)@CkA*Z#fRpj$1%%hvgQY|`BrlZJi&0!-_muC7^O}ENRN6u($`t&RWD6Mizk||s(
znh~d?dleNGBdVmS&lGj)LIK``k0HqtCF7CKeRgwdCHxR=Ws-o9rgGJJ7OpuQFKGoG
zf>&O!JF*_)|0-GLkSZY3O}l9*v;73?n#N9u5^cv_v*Y6d&!4i(;~EKL(`QK$+?1V4
zalz^v9bs<nRlNZ+IfWz=3nR^#Vso09C4m@YY#Vc6u}UHHv=km{dZ$rCSsbJf#XoC}
z&@)ZZi^mnrGry&nQky&ntM$);-w77mo=V4^^^Q6AVC5|8WKCe0Tdn^`Q$S3hz##Qo
z%S6>7awn#f%OSLC&i9e7WE|CJPC30<SyJq5`+22dV1$8&ncz}8X<`XMUQ+C$M>Zsg
zCUiUin=uFma9*&WE`W$y*TYwDnstnyueFphRjMvlIKKD}%^$)G@dv=_tQ#n*2yGO4
z?%Y@xx@H%u*4bOUmnPgo(m#!!#co~A_uqMdbVURMY->30KdtUAwPGs@Fzh>MBC*Q`
zex5PdB5#L4a>YWKQ8CBbSzec1YNq^;Hgf<p;Wp;ON<>@gY@2Q%Anq4#a<gv%T~27k
zfJPr?uXwN$(Z0QdJ#(?KstJrNG<Z9KP|R`F%ukSr_A7_+){<8JYo+2pYdJMzs&NSb
ztqQd|O}3=xDO<07*cAmzG5_7^Lai-aIu-B6w{lbCOoOXnednrshN&p=&k9hS1kyJ$
ztcMVgv=xf~@`Xj>WlH29RQK^1$bVW%BAUOkSqr}ZdOeOVFZQlgHYA8E<Zn&)YgSc-
zQX&TEuugHHSm+k92^~5JKcL}XIwyl?9Vep-C+A;aGCk{JC+i;{Pm%W0e=t)H(@o2C
zu_P9(z-4LFc?Yr!(@onDskEH3VH6_rC<L8CvGB}E>G5q%W<alw9*zTk7!Rlf`v4P>
z#8PnZrYi^s6<9`{arJcr>!COQvV0;m2b;%6@c8tGA!yJo@ISo(C=E`cHbWdS0CGn8
zO7583?CN)SxeGhzf|ZA-0C!DcwGP^AhbNF~KkfD2k`;CjWIVzVX_C48RY&Xv{h(ed
zF%szVMmWRrAe$$Z(Cl<yGOsI{D8@Xvx#@ez+{y|0Zt4}h3BfpU%FyIIf9>DEZD4bn
zo1R{`oB$sWL}+pL*IkHY8#OU0`6s>!IcfKYGGUF93O8o{11G~KrId+yGd2ZdS5)7_
zLq_is_|GEEYir-v!PgzfiMQ;>8~tYG70nWfzk@&F_$aw@j{7TaCT%xVh(&*2dTin<
zrgA>D+kE06(-eF44>aa+L~+&e581~F!6YiGbEbR+?@UfOIfZ_N@!Nh~V#ghDf98S(
zGyrLGYep*Z-H(AV!eK(hK4v_u<W2tk0p9r@66GiRk4oKA1804}$=KNwA{Yq)FB6&P
z?<>k3)R9Zqm-}YlTzpjL!Bnst4d)I&Fh<0_8S5qjqK3mp1{SUy?O{Jd+ky$#!x?)5
z_n8XDyyJN+FJs?{66Z8BIQs{w%`dYLsJ;IuQXoUcZ2DG8oLS~5#1SASHlUv+?&t`3
zZ@e{94@U1c0d{*6i7Qn^yz3z*ju4)mCwT99YCC|$#ERQm7FMI#dH<w(jh_$Gas2d$
zpKKz1pAp_4y=GI3DzJb681IihY<<_N%Ex)S)4qOFNqv5qz$o{b<(4Iq>W<pfi+`hP
zo$<%n>SV1^-mo`8$8lgN^?VG2wX!!hKsFSJh0}tB;zQhkK-0wyoni7tV2m*dg>mmQ
zIIT=0iT#ft4!!!>6jeFP+XJa_PNz9LC-rY&y?w9QU1$$9MFZ-uuB6o#;h(=(u=0RU
zP18(HBhg+Eq5;M1>ciBCdQ&JcFCU3U%BHx2{#ExSkxU~%zTluz8t20F-H8gy`icoN
zc{KbO_RTuo-1E{#?^-39Cl(3d^@9X6pesC6f!=Z-@^@yQ_n=gaqk)o-AtGp+b-FXi
z%*a&;{Ai(Xv5JP=Rpfq44W~+_(RDBMw_waJ6N?72L^<!20zfXT{;T0OTf%_*`3GKu
z)1D#Rxo+V@#ku5G|6YHeFXS-gOc)oZ1?lDKbIcksJc+<!q|X<JjI}<Y2`%a3S=?I;
z1rlWejF))BL#c2)hXl75^GlgJfWrN7w(x=z*?Yq41GEXPBXAAif_g92n<C@z^pu?}
z5h*oAO6(x2dk*YC!G9oVyd-0*wx&&m><)U4buoI2E>EGUuC{sDiSR6Ffo4kmfsrdU
zrPj~YnG8dbk33bV!kCvWEd+DxDaU#p<Th*7^)|;qtPt~sOh)Vi3eX|I|A(@-j*F^Y
zyMTvKL<A%xMQ~{8?huCVMpEfUy2Aj52I)o`>F!Xvr5hv#hVJJ3?cwn}&w1Z--tYVP
zYXo7>-g~ZfueGjq-5aeW5NkNGf~c9AQ=>3&__2YU)q}D>6ZeSs(q@1VQ-&hrfdTy6
z>|CA|pP+bQ2?SWf_WST6zQ{G!Y@(6T^ARbC#2aQX6*Bud3znnQ)&3dZwwoA@ph8^~
zNDl#`T2i9}N+V{2k#3>b+J?P{fq0~&%wR2Ccs2G=jcPu=PfT5YHI+C>n`J~n2yxw|
zsG>8EBkG^V;B}g2F~^D$>}@P%ky*@dILhX?tY9F8OpFMqvl!|AidCN`Piu9Cr|WgP
zHS_zZwLE3ppk_+IY9eh2&xT=Ja+I@ubzg~_v9Pk{9cI96Sb^zE4S;@a{`5^WTzvuK
z_M*ouA00k8wup3~;FPSa#yOstnz6tRl2?hd?v1~vx=-)9GnvhnUsxbOd#RPnkw77p
zMj9uHcY{VOTGvEa#}n<|B-RHB+Kv~J$<a`#*|U-Rn*GjH^~@;@31kGPx?Eohq=^0_
z*+q`8w`zFLqp6H~oM2(fD{W*tn;ksgb@&TY{vsRA6g`ZPRwJRtxHhY)^3wmFzz!Cb
z53$F@Cv8^;{tC>&mTc-JYlTvCy8ScH)q92S{^~g!NnNXCFhQ$F>k+_>g<m{|<T7gh
ziWmOATOQy;{MuY9OGe5=0`&`jlNN=Zn$N=FcTEY#k4N(fa>8k%llX*ny@F9FK%T50
zyQcF=OUXuT@8Cl1X~kVeAQT!)%EkhodHT40lnu<hU7X-ao%CE*Y5Y8l5cKx1mQz*V
z&m0^Qknax}X<}d;VJ{{{K=1CQ;`qin1@pqB>7<i5N`i<vqv8moQw<Wx$kZ!zwf1GF
zoRKSon~jPd0%#R4kr_i4Zl%48)BNV%bw3zjGctzuoK0I>kN}p)2yOYowU{!UwVvH7
z8O-3Ck&oO8k*+vB=h#gZXm#`useI}w5CX-+2gd593-$()*1q$*NiM{s!Qy5LxxY3K
zS5lUl>z$zId#o>`)E<HSe|!^{Se?&>PYTRSQESsksh-OE{|JbZ<}qs@MFBmycz7Z`
zH|D@w2zHVMxe89lRZD0cEhfZ&IbD>)<B^DN{gOmkWCz|*c+A)1dG?uxB<CHZazhh`
zJR>x#a!Gvid7=i8_wq_p)}npD8M9QYTtEwSuapSQY5$q%H*I264l1j1s)^$ak*gL<
z+fb1}+CR34M8A1fA)!o`npZ)ql4Pw0@`XEO-JxmqAaXP!oP8iKhHh5`@6}2@D;@jl
zJmg}^*%7Kd^HV5G6-~kC%TzxrZcS%nK0NM!@UDx$Nz15>a&#Qi&_kqB5vV8HM@#SH
z@4R1ToJhbYewx!?uAkGad{GXP=Yp)I6qhh4e<Hk}?=kY3Shf$5sx1F|_`l*D6T85d
z?9tcFpVAVqiK7K2hT!A8tw48U!WZ!XGEdSVUpN^U7O*vI2`8@)lF3R~*7xHCo^2J_
z0l1U}T(A>!EDHlj<wPl!I6HM=U=bNG?*WBYqJAtLdHHnM{eJG3hA@o)oRR(4KM(-8
zc?giW*koXq2N{Ii#9=Tu#92ZL7!>M>QhF`+^E_XE`b-t!z*g?e2`3UwrgWn&K;h{%
zVu^`OZ`2LmNp!?YRd%wVlV=#iiQShDDUtPlqt*=v(EcLnjGFOAozMdiFwc^N7+opT
zn}0x_%4dEV#|e1ZU*;b=w2TRmJJk%W6_{bE#F0edvEXO#jm=*urw;Khi?vaK!5J5T
zaTncL+8};dO=FxV87b{7{#a!Y3*?<&)H#uZGjE?|m91LvB@u{<a<e181^X_aEzCIm
z{y-WLfauiVkl8_buhu0~HY}a=k|xsxTeIGPK$zHwVd1aN)4Psi2|@OBbcm^+zs*R>
zEJIMm_>(3}STriBIGv_*{CNdiyr{t7nTUID{_bwNA!$l{<Vf$>M{n%MLmMK!kb#_4
zs@I#2ms8Y_*}giyV?<ORL43_p?-xw?k~61`p5iMp!=n!<9iztxPo5%r+R>9>M?Dxu
zN6lb-D*nkX9gFcXNgx?}Ja%KcotA7sBwLS;7`U6WBS!!&a|o=5o8FMO%tfn2Dz~+A
zC(4w!e09*sG;1hu(^#l1@^KY^eQecUIO3W_z4J?-9}8tM?E%B*Pv+_In!>^=%Zb=}
zy~VIP>5<#i9NCvK`dT5D(w;db(JCTn6Qw!r9F)zrx|lf#!NxS&{VyvLoaSrhngc}e
zvOg6%wJN8`B%^n`kZuq0g2)0{yzsIFEnOB$jG0dm3OJOON<lE|CQC{-dWU|A#_Gg0
zvAC0^T*3{pM$E=)N2{^;g2rd#p<eat7?#pHXm1&&dvdUK^%~!Rv7B(&SitpIRwKzd
z?Nt#Q2^f~ro}#QSBYlSaqJ$YTa}3dM4+JZU(Z1+MAYz{NS{K$JK=&FZUR*rrxjTPQ
zet{&gh(mGr>+rkHS7h$aZ9gk_)5)9S0UD{M+mSrQs^lpeJ@lzrlu6e3OJB>(-e-rR
zHzY+wpyW1tdkL}i&2p#yK%JLN4bSuDgUYRLTL~tXy_Po}T{C2$E}LW-jDU(CQ@6j$
z_BK(F%NM;_PsVl+A<TT@RMVW_(eSmsssm-p8x`i8y0__bTsUMiz~pJQDpHMwFQ~W3
zppiG2W6a!hZ8?UlgRj<7mH3(jPyUrYk4er^(s0WBrX5!4i8lEfQ6h_d!aT2{H(f<f
zB7yE3**0k2)n`2vVaS-+V1DT69PEc76MyWrR4W_F!h1w7M*hc-`alnjFyBM3)?zKj
zgc6ZKJh=ENdXSrsMvasK%SZB4;yRj)A)6K2^iyq+^n8)38eSShp`S`t)sdZVL9XSn
zkGKy(3c?N(V#Y8TvJ)a^B==CuZziR(ij0F}q>7cHwa#%WIKd{M_wv@+y>y4jm5BnC
zQV!ak24V>uEcNB_{#Z(931MMj=X=5s$D4Rrs-1xX2lU9Wi^nS@sfLY@rRffjK6FQG
zdcAg>e^j%ZmsW6TS+lWgPM^Y>AbWSva+^7+^b`H$Wbul(!dH(aL6$#765=QtPmOew
zB#pZH+tOwQW(0vi#^?aPeBy|}!2+(gkk`g(c+!GcMkOxLo~Vg=&&RmNj3wKk8&vl_
zRxXTDX7Cmde7_{e6=rnuj8xzUT;eQC!6u;9Xhr6m)0`gUH3&vG?aP~`!A?@1NWQzN
z&G@GSdBgGUw_hVrr9)TphJQ*QAo>H4gTsPDo<Y0<e854|jZWL_3eWgbjt7gcbcrJd
zNXG;h-4;{a-4~9TaAeUfD=->3THFv4vJCaiYa_ij$t+1qlYNZ9U@$Ks@Ht0ieci*<
zpWn0QOLid<wPj}d>=nlr<}1{+Rs1abvb?-I%_il1uZw8xAk@X=L>&y|(d<w3{+Dz^
z;68rc&Zg!Wk%Wb&N^ro(;Rv!0b&Ib2r0zVO{NWRiJwDLXWl@8lvTpij{4m-YSs$8e
z=2~mw51aVz+{SC{o6`y_rs0@(tO@QUh**&y5(u#7k;B|58yz*~l$U3gk;19d#Tu)l
zJYq1)p;jvi*pqm=mT4xwvinLF1}w$2b__;d=jIP-ysE9|m6sE-3ADV6wHg)pkz|4o
z+<wED&YmU|B+EY`XXi3U5H|^V^`^W2Gy}Qu)_(8pByT3|N*)PH!mrF9IGL2<nS^8j
zw%BTv+RKj%e3&sHoS`#9z{Np(WF=XW^h2D}hk4AlSa+B$3+ya|GArV!cECsiam;_z
zgy9R#Lt}kS`y7ER|8hv=^!sg3&lHSFX_3CEf=__0Bv;hy<^_mZLEQh-7oRblpV72r
zIQ{h|^ulGe9yM-3{i6~~k{2jE?0(CA^9`7(QYIj$l`O+dMe;SXB|`DCT5b6#d%tTb
zSd-VD&273S@1tBQL<h;P#2<_#Mku>Y`YqsA!zQnhZivRSQD$(x6|mYSwX(FF3#S6G
z<)fve72=|bBeNG>kuxIg>eRgkis)}CZu+7kBDi+ih&`#pC&I2W5Ql-*lXIyo|7MY+
znFlX|<$Vce9X@UCVilq31ItbXix$J20p3^o_DB%}h6e2+EAc4XDEi))o&y4G=C2*5
zT47A@RHs5}f&#nxs4-+5{eTs>&mSldLJYKxGsNtnY8Eo5F>;M=k8M}_izr`H-o_<l
z=H_EN;RxT}XTLo}m4!7QGM83z`?aMQ*>h|J4dEWXfVsB$a^}xWIpCiilYeA%Xw#Mn
zRw<oJJ=eTbYGLIv&yqE{iC>o8Vd-#`l|;9!2%D*c#BuWmFmyZt4d#@N@?l-=d){dK
zo`0@^k%7Tmc%#F^Sg@0Sp~F!~y7)~}@%i;^L*H^fE>5!o193%IGPe7SkjtA4aJ|uI
zZI`hjwVNt!$20a=`2^XVyL0`!VHnMZ|K;VLSIQgVl6YAvfXit0T2XbBP3uW0y>oK`
zU+Kv0(Z4nMWKN*eRopJb<#Th^ya0O&%|iih4{Y-qxG?ra76#Yo0Z>MUsGfE{=cia$
z!yN7GAyCG@fMOo%^NJOnJVOSMZ&+BmTrq4x5J()bQCdAq5UM^q5?Su&kDE2jwX68A
zd{!a5b4U+kut!+ZlzCm=C#2)5z?kv@$e2UI!NMAT1BZ;v>-Vcx3%sYCHbSmv-@Py1
z^k40ctvDDfX2-mLC(GK#BUpB$BVcP3=4LF-zefhVjYxo1$VH$^d%u&HV?;sj5lU2*
z;LCrLZ74{IHD;-^W{{|WfvPO~V9c!U`q{v9HgVC4tw)>j-nu1&9AWC7bta^E2(6xr
zDT{>#zl=YgeAg(@?)a=AzpB-)o*x*aZj@={^0TKJXntt}TSnR-b~R$_)zjI~+F2ib
z=)(C4*3(9r|C>3SMAMr4D5&IYOPhTs;_TI*a9Sx`S=f4e;kf*(8kS%r&Qj*<3lN9K
zXx+&pN-yNBLz!SZxxk_082f?Dm_8Sf6?yTzs&)DA_!3M#$2X+ji3kxMkwllRmNH%9
zp;86!VD`PE94?wF%UU4I9tSIGEG(=P;<Rm92-j;W8b5Lnh1%VlZo#QNGQuO-@L&*V
zn354!8pPju(fP@Um5g2^G3F=AoHfztvX==usxkqHxipKbdf_2i^PZOLs?Q_WoHm6-
z@xGTrW461Fc7yNSY$Q@T*2|q_U(5IO71NIS>k0-X43Ivl>vw;vz)u_70fj={f%f1$
za@a)&itE8{qtPI3*^qb+6$6Qrj7>|wlpb+<&e+RI+{c|x4Nk3W0u?XEDP)Rvy(3jb
z!dWtDP0}mDLPZ`!%kzqjG*q5Taqqc8W2<-Zq~9kZ{3?xTKUm^5$(c+OFXIys#7ti#
zk}_UT!BG9t36q{$t6@!&n)7JMlmjMcYTy|CB;diZ$A=NqS%L`Ooz*h@7c#dLzY;KP
zxg+UJ4LHqrrN)?|yCOvoE}HS?t;rerM}l>c%2Bx6Zw|EqV!(bGB+o=70h8F`c>6Gd
zPSsKe<O^Tp@fU$Rvo_YAK?q7#(at|KOZ8QEu*FVduQ8UT=uMU9`T&JO7ajsdOe&%P
znGEkS8d+%MoqW0(U&5@X@og)0B<R|cjFnPd|LJhgXKj~P3fK<8yQ!Tb5Xa|#6`8Kc
zdXMm3j<U$*MdIvvF%eK%)c;)1feJ17$nn>nfiD1Z4}6VT|JhKm9@y@1SX*88JR`y1
zl82H)()&h%*;+?622xzCMn%&xHY$s&DxJGKo`v1nfszn*5j}!x9fYdyru_O4&A!bs
zcZ^wU6lFMJizq2p0RnLZjOq=lO$wZij|R&J)t35!meM*ZKh6X(if|E(IBSS!c-CVE
z_w@C(Q1Lq{j%YnN=mHKnKRSjfSP5w;SUI1)c3U`a<~uo0CQYDDkI^WL*3~yZd9oYE
z!ITDtZiE2FP*r5uc<iS!Geh0%C24uoi`59Sj<FewFG?fRsGO><r^;!Bv>)79S-H$V
z5TQ$)s-t8kB--_6#~b{h4)Am$k5)JGI@M$*(xOG|h_gI>ht<l`G{Tbh<<UfOMvh*t
zxF}tR1%WN4Wc*&kQPSEW(Xkm{fqT{bPLyDdym-M?VbW<<j)t4V7BwXp%!~AO65%P9
zlc+o@IwL6vr2399b#p&3+)7>LBD>=}>p`6XZ7#oVsXs?YA?7n#zV$0?v`1z^NHj&=
z3K~ISSHdH=sd#qj@%z>dr!hRl5h^0#LRH{E7D~bJk)Z42iVT;L<#|Q=*FCn^)KfS=
zO-Polga`3VO-K|cLhT}^3;kEzbNZ)y$>)3y90y1yz$Rok(TA?2-1M!NHlyGzcR9qK
zwI4W?f|z+qKFlO(dzRaZ=tyC~nAoMEwa!8Vt(!D1cKs61%}Q%{X^MzS_5`QG<CUx$
zW-Ztqx4V!j+C<9v%c;}fM5u_M4|G}x!VGVvRbxxUCoN~rR;L#s5XUt*6o020FvpGn
z$SL*uTiye&$sgo*qOEKs-d}_ysgQn@AH<s0Bj=taa8O9T1GTn(@t$`l24SGR51;Kl
zvcbg>)P#VTF{kX_hAhQvEFXbD99w6!OX&H$RV?xh4IS!iBAh<Vt0Njq1V@FWpgIxn
zycToalO~XBPUvq)Fr(d9MG+M$^}Uauw#VjCuCPjqPJ^;{Y|{2wP6&A@B2atX{R6F3
zDlQUVbBfDjlsb>h2)qP?x1K9dV`EjlJFua#vpztm*8jo#D*+>}#RhjVqMwKIn1HRb
zCVY3oWgFIYDznnA%S-iHC6qkZ5S=T-ED}P}XG1c@urZ$0Z-Nc7x|ukPS)u6rkWV`v
z&#v7+9&)7q3E8(zq})2ZI&5~wP$(zSIqU-S@nyb@heJi;YkRX6>LRK&bbcsw<DTWT
z^HeQuR~8YSgi|31V|0k+;w!Z%7JGMpJ->#cg&)`V`fej&*tLv|E_<zG#0*UaY6lnl
zDG;|!F{u)@vXO9R%xIHDm#qo%a3-;{y@XW+m!p7wPKJ-ca1?sow*9)k2)#);o<~J~
zm_5G5y~cb>Zu?S_OryK6I6qN6AzdfgJkOT{bKJW|;XK|V*n2R)C|Yki$wPV3ie8PR
z-GsJkDk`XH{57G>>3BfQDfJ#Q7M2oPPG%-~RF9*h;}}d53T6BPN3bm?T-#th@|lR^
zlD9h{v?}0xrBYVI!auOopZY+`5#vV@-`4MMw=)dR`<M?Q5CH?$1Xtcj=*Cu=6dTSg
z!s|mcW!K5`tvEN<pDk{LyTkeu;O^rij+z584lp=_I1GTc)M6L85U7@cTnM!I@x1{9
zg}VFxwRx*j&7Zwfw>SX;Vw&|T@VT$S59*5tD+*@WQ#nq&>wL32>_LI)%Dk3mvWh|Z
zrU}nlc?<+;A9BoiXF{P+n};R_5XUGTS&OfIRyJ|^?uea+AMtf9!v`ZTDis0rs&`tv
z5Fb1U-1)ubCSli4*Jv$(g{4Fe9M3w-&^?<j{vn7%i_uez4K!xPU0%aWFfis+=9=bu
zh|+<#g8*XsRHYGws((>rADUMQhBX<yzL7pyOZ3vTnr<4$Eus?34Gl(3d(OJ$VGl+D
ztzYe4o76kU%l>pNV702NSCc(og%o!{ViGmooa~p=D-?X8&<!HE788+2Mg5{5uM*XV
z@cPh2nNS4)quQKy(@SX{%F4IsFuxKnm^(AN9VgkMSE&%pY{R%_xlfe61|>p=F@)Am
zF3|SnbJ?1BmRx>a2UwGTBr@nZ-rJ_4mf0x*5@J84U`vl|lZ(&;TpTp<m3?LBCQtRB
zC$cRc$4tdQ0I;Z3Nu?MHE?13T)7KYb3Jrj|n<UY_epQj+i@G@>6jCb8d4s_jmhu};
zAP8jsZPYqDs$`d^-$Cdg##P{61Kx`ZQpD8F{iy5Ltb|WvLu>d)DY>=Jde`l2k*8Hv
zuDo4CB$!1V1JV4jFB7j`JgGaLdTy9{f<&g#jd_yP_i4;&=p|D_&im~c>4<5(1CO*f
zqJSKKLceJ{#lQ(5&9M1&FAx3DPF}^7PIVY<H*HtP+rq(RuVtw+dT|JZ>$xRx6Ez!&
zrFFDDeRtwYF<f&(6TjrN&#v2dw2MqQEh2gpoc3H>HpL_=hhD$Z?ne+dVM7Hu!&+@#
zGffa`z!9Nyx7yn>OQ*=fB^z7Afgg@3;&R(IS909+$*Rrv{j$HgGWi-tSHSN*pRCn{
zjALP8%^Lyhx7>2_jG0QGMUMDQrW7bb)NXiFY>Y{=Q`??Ka1Z%Z9mRMX#n(uaSvmMa
zb_WkJ$b45y)T1>@m&-yi)ps3ve-|0?)5t5b-WQ-!DK?yPy*k$7^b*qiNnb*SdIjt3
zUX{uwgHnzzw&fq>Ud0I0NY69s#8JpJ@+N9QAOH>Wh0@K4?RFS*sqh9aF-URRVzETs
zoB;J7zqzr|ZNy4KLUO{34bBKQVoj*zDsd<2*xYdXhTikU=;O#>JS$~JC0K|Qdc3vp
zsVOC8W9*;O0}q_B5-&@YDo+8fr?(pEZ+8}sxc-Q{z|s87B=yO$t=?41nF8&N=YX{*
zPbd@$WyG^IfH(^1b|eyDrQiUs)k^>H7^HvWF@IM+FS(l3DhL-xu!o7jM})3}vuKoM
zF~PP`N%lM|-razr8#&zC`5O28<^GtNS@zVMDJQ;PLPxAjZ=azf*`u1qA3Txa9$MV_
zhQ~(KM-8seIp=2q*GrAC=)Y^+aY#_0uBZ!5=>1e-LIP5hJ%7>hFdD6Sr{QvQD?&m?
zQQ833O&7_%{;Vs(gr?{-njzNSv}oaW>vW3Gv)^r$AXA->4xY;^zrQ&Swwwygu!A!e
zfWei#P)AuNCgf32x_IA%0JDd_f2d16Bi<g4!fpCgh5+c7ap|cv%Mx9S+HK9<NKoNf
z(1U_;-+q(R@BQ2RKMx(M_!Z?*2|x7(##m5{e-l~R?)a>LanY-5k6u96tW$v*oQEnb
z|6El=jno-N2IF8V;_*d$BZj6Uau)Ztd2i4*$MW|eGE76G$mSW2AWx*_flx$m2t%9#
z#1Z{|oj-SS0E81Se?xZ8-%<onFB8$VIqhdfu<z{c)4rZ(-@R2(f7o=y1(?}jlGW)D
z0OshT2zR^<i=n(*{rZFlI{BNr+Az#UPHvNZAB@XCS%93rmTf$o@EYB#%U`==i6^fO
zDK@8Q5VclxicJ9`DI@8nUZ_oifmXUuj7H{LWe-AsSMvnB=lzAw9E-%v7GiCL+Vh$K
z9TEJvx5RckITm+nKUhc)W-Pq%bSDDROhBu8S^k3iGg_Fl&KD5KB=-MuM;oJ%f|jp}
zt0cT%9}0PYu(}miSVHa*s`V_@HcRR@KB}FZtZ(Xa)ntRjP1%38x_z6ckJ-<%K3rm)
z%18=X53vK2QriRMrp1!3#8R}JJtT^5)i~~;&(Vpoq2nQF9l>K|%igb1(3S%fd=`i$
zY&cc)5t+Z!c6^3~nhl2Z=LGg*e|~h(l;6$k=GUzb<C%Rj>;2~qXK>Olpi>qz2)3Te
zXrdhB%HNH0M$%E?l^0*(O=(vttn0&y#-c5*ixU{OTqLGs5q;-*6>nq4YCj&!XI;Xa
zJo}n2+0l<r46m~7j_F8nGWgJyrY?&j?LTDjPO=ohYPODMijdaA)<B6rY_N=EPGl^X
zMAU~r%WMo_W1vyTlssn}y%^XS+&!*!-7bZHJ{S(dNFa_;+_{{|Db;G3x5E^m?yt2Q
z$KWk|iWLSP+%y+NkAhFEr%1xA^aL%e81xK-(;!I)1)>?G)a`mQKZI7CpUI$w6ydju
zS`Q%8NFYvg6A_F@eKh*CMV`s}k7d<FuyvO=x&jlRX9;}lG(}sJ)zM3GwEQ%NLduM0
z+_}}tYttuniSpmaiw7s-gts`}R!cc(i%*G5nqkaNKQ*F@?aZ#Sa6l*kvA(Y3R&jV5
zCbQ9jeM~f|I^fqS_FCwBZE~U}d(Df}sWludU77#JZE~Xk8Cvl&;e)K=3}M5D2XnQC
zR%99`gg3F+<#qMgGS@AR9V-3~u8+?G=h6hpiG!NY4&J;#s2_BLn@Ru$Sf3|{)cV_f
zM}nTa)}nw?H}@aRTeq-vK=wNtjz|Wk8pxQQ#J&H@c)0ZRcZV!MZvY}<tveta0v+^A
zAi&anMimw4vQ736egk~X|JiRgZx#?qDUshO>_I_*^BE%aHAemHoO4D(!Ay}HC)&Vb
zfZn2Vt}K3Eilbx=QXIc8#@6Ms_a(7tpO$h(+R!SOfFX}v@UGsRXFMjAp5%xF-PN7J
zq|loe0)ddg8AeaXHDfWH7pcE!ZrsrF7-MAVwxa4_Ft!;Px!hSXEz>?&dkHT#{)sAl
zN)R`F>y1r8LmJ<D=xpL7^2LPl$8cqw;7ifGHk{cHZ!h^XW7L26m37V@a4_YTk6>_j
zQCFuG{6^iXWW&b7ssch`aD?33AoL?*z;DhV1X-{@pVlU^qB+-WRN%k(WRP^KD3KjM
zbF6N?l=rn>IiZ7dc}C6{WOP(}cDw)cwC{O(&LIxDdvQ6=7)tcXmq?|WeDrd=k(qJ0
z`%~yuQzsCiA|f(CkB)BNd%1fo%QM8TAijLmx#CW2V7W_h*z@vrP=3|RXZpp{0Uejz
zbba~G`KozAsA<m+$K_PDB2NMhUK?r*oXuYh)L%2>M8krtoT|Fi`wH^|W4hvSP^fRz
zz+kWiaGz|D$%6rY_F-$f&M-g!dc;6SWtq(@I~iN6)c@qiWV4e%ygxT_#Gc?(niKo+
zNU%oHtmvF_PP>5tf;&1xW3;Z&t*W*Y-hXN(2@iRGAs9u0Y*iQp?+zS{6=Mk7*D=G}
zPk!&2(b-Yn$nq~Z@4(1wRX%-bc_$1Ky(vni8Gou>utvSJXWolzA<9eN>fW%Vk~i<r
z6s*Y=1$#39;aS^E)DC}7AeAXb`IW(;e^N;K4cu`0pyzRYZ#S9s@u{ej2>Dh~K%r21
znZMcHrek>evqcvM{zD;T{?R4s3%IvLZ0nXI^S*jFW?*IEQF;F94#R@!L<E^10tiVa
zrMQ*FWU(g)tzp-Wxc_YaB6oAL6jOl+=SeW=?TgY(V=t;%+&j;KEzZlOgctZHY7Omv
zBB+BoWSD60!(mdva*4COR}yishm|MVE@+h8eIDBVdGDbEWmQ_uUGBsu#J5k}1WF2;
zYG0~pWVz%U)=XJY^{!+3>zEkA_+crrMagZ4b78!}1IDoUkI7%+bXD?Z6SiWBR<s-c
zvavQQHF3zn7H!M(ih#Xu)$-Y?mCZWZmz{EfGwu%-&(;jle(j292@-MX)2I-;QC%{*
z+6tOa)IXo<R<I&x^lWUNO%AQxnZ;EY*s>S4zsk0AWX{GoNzz81o(#7q&N9rDV#nBc
z{zA)Ji}4^v{l}6YKEvbiqPUWR`S$`P1ud@Mw8N*0kUAe#HMnbX=X<WjCk)z(yEx}|
ziM3AHhDKYOT@H?g>3hR!6+)rVJdz2(ow1X*uFN;)Q295M?&To-pC}!S`3I#FXOVtJ
z<w>}6m<ykR0(_6)LQ+jQT0qWjqXN=cjfEeJW_Zbshjz-0wUJ(H>S!BcO0TAyg3c1&
zw6A$ceKHb-vtfxba@9{l6s?W`T8_oGoq5`IZ7_V+efQK?=?81(=C<+C;a<(mdu@Hh
z{7K)sT`=pVef1o5$t=}?Z1*K(TzBBvHx5RSFcl5H=@ur<jJQriUw)t%8wig5#_ot(
z1Ntujdu>~|065tVivNb;8tvv7*3L5KV%~yJd9HLHpDfS%8$D!wZEh-?fITEYrR)8-
zLX9ZL!8(EV7%c<ade?vMkNR*s;J|O+N;M#Bg@W9}B>C<p@8!tQ<Xq?E5}-iu#p$3v
z4i3eg*aK0n4>|1~BtSzAqT%0Tw0s8G>nltX5D4V>bRXEW_Wx3=9b>&6c|!5c(Ba^~
zx1%?&LI?|3zbED^M1)-o+98D)ny6-ejmc>k2R!iuxV3H1G7V*{sMGa!<7#<2p!2h|
zenh&KdBRouB9Rb1%q@Gxqnz&^S<$!I0c2J304Vf~WEXHQ;-NC3mnWot|6-pf$o;nq
zY%q6G+QP2_aF2`#DOTO6h3w+Nbe<gtCnKCxp0KEz^wYjfdybtIua&O|P{-9Mi!OSF
zmmMF)2YTUlIT|Y*568FES(c)3>egGoag=RgV=!8@1wx@V*uWA;z8W1tcHzgvQTO~Q
zg%5QM3&(%!puZe^xY~euYD(g6m~{MN-6Cw~84lVbGdMq-b`ofkV#M!^uFXMaKEwS`
zo6}yioj(+0_TqWK15I15c11qJk=xV>%_Mt)(cDjh>!Tbsg6qs*#L;G<mRxGu4gc0)
z2i4){f4y(9Yl?ZIEzPJ_@OpzRrGN&9`2pi8#F2a|i$@L-kOrQa2V?q{%U8vI61M@q
zro7h_J`u7HKO3(w3^}3>`mcvw{0w_KV6`dqrg5n7<?F{tpog&`dTU*e7oFy7R6R_R
z9u5IMx()Q5=r`vBO<OL1%bF=rEC1Urgb2VwKQ`v={Lk3bX;a(oC*m|de!#Fmor>EB
zFoIk_FDVh@?fGL*;*q|+qAWy8HP5ulrahRbOLnk8TN<VStw#Se>?hzTYoP8ov?ZFG
zu$^a!CNk(wVU}Hq?|js4rEZ}f;1|`a5tgudZQ^L^;;w^ibu%GZ=bw|KD!@}1qVHW`
z;t70g2>@9JkUt{JH`e(|Evf1~e_%z8_8+h^&bVwPEbosnC9dO|6;}te*j?u!fX&|a
z%j-t6>0y5r%T&a$>70Gq^G3PEgoqOmWZF=t|NpA|R(^yc6PVS=Tr8G@6a3vI|2K`A
z5Tm~O8!574F<X(T*IE)VOPxETX%FTMvHw}~`{8*1aHX(W6&_x44cWDMC9$)Wkvyen
zA@e)Q^p_OUcZh4r1B7T(XCeWXu7XA*l{m!oJMj8h;a?9HIsyH8V2_RAznSlYl4{sI
zppMT9hiEZE_RFf6w-!b5`%)|??fH?YFJ=qfrqY!W)5UK-;%d>RQdU;TrT{g67FmwR
z_HCH0_#+gW_xrDkr~PnW@jwr(?!E`6@YTDXclEo-tlcXWKEQ96zW3YNBBo`7w0q~W
z)}DM#F}L`A-hS$E@}y#%XWSqV3T5Q`<6R}t#Xk(;{h}XnEy9i@9O_T*QSfP4wqXH%
z$3eQAIslnA=LH`<h^!*Pi<ym&zfxyF&t5uD*+DyBUY7xfBTPm1d^Mt^T2=$zFgxk~
z8YazB6~7-t%@HIs(8OqD0k_sSXLfp!VZi}^FaeKGC84YmO#F$|@l*;M3rkl7=p~3V
zj|BdANKiT{FGd-CYKn9?k8)Lk0h-b#p-+>4KIbeD)lWl(_w;9UZO-Soa+rHqWMxY(
ztqQlZCWyzFgw)mgeZOp6MI5|G(W2v^T_Kn!Uj&et&1LOJD51$+C$gBJ{Gp)McL)=+
zp!R9sCw2waUir<FezNFO;yMlaGlk>-SyvY94gKA5!x0h(gEM5L|EJT1-ZLkK|6hD^
zQ@POw%v0FWW6i&D;#kie?D(U!B#n_2@++KxoZ2K=Z}uI+uAR2qOX6<i8dx()4Be{n
zWHeT_j1EooPn5rmE<4cb<BPAi7<hV%X!tBn68{DrBkWdgZ50=vUd9oE=>GtRqZqJQ
zjrspGd}BI8qh~IC-LAu!`}u`oXI|jEz(DC{3Y1#0uH0DPEAipwW!cRLcVAo>>Trtx
zCLAM{vvS5_3FC?u>$T0kA)5qW?r?F=K8s^CumJrJ_iMSV4N#jkGXZiCh~p-3c&<PP
zi#9iVx|DzO!^sG3d%m7G;!FWnH>uh1B<J!E@}?;cG7n$TxjnO~{ig6EnGgBB+!->@
zZ@5`-4g?(n9%ifE%*3)b()ytoZ%g!^&A|gVE3Sx%IA+b6Z}o+gOFksZ_8k6k%u+cU
z-qu0$VKSzF8hO~(e>L*zPD*1;M&@G6%y)pST>Y`EgoFfD)aJ%U-elxcEM1DIo~$Of
zaTpC_47_zW5;co?`re}c&3|*hUc%V~T0`KSc~)9UU025oSy>3g(G9o)lYrC3_4NO@
z-KBa9VKXJ72SnaZX%%2E>w+xCNM+L)Ry*H)lH=MpOKc*V>KS2Kd@zTV)e&OBUOBS0
zehz^^H1Gi{M2eA0?WZwkO&?RikO2mh@#Ih(+t?Frn2q;R2#+2g&{{7%z#1Q@;9HLg
z+Y{V-o;KxOoXS-?+Aj%#I2r@*#)6z=v`@z!K{|9ot?AzRo)YA<Fw^JKVp*bdvC2DD
z4Jb+@IXz2#Gf6D{Zb0Qc8uD{PO)K)|<0`&UX6N`+?YaGcApHc2dV)aiXHR>{2m_03
z5y0?{P`Y93g!78dSAZ%Qs3&84U02+#u50^mw1W4%77B$H<Nc#K2WuHB_`%9Qx)j=J
zuSgEZ5e2OXx>)<((Fc~AD*cy=-zyEhImt|e*(xw_gC+g_jOvp9YJKf=S%~wQD3|dU
z66xBS*+wmV!c~c(%`}I1=ed1Hg03C2H{y}M^!ZUsd%j3WKgJEV8$jeBx-8siy31fm
zb;Et@Rr4;Px;G>GB<n_iVHw1lG`^uT6wN~{O?Nmt6tr-~lv-TZrq%w$=%ezBJtSZ2
z_NpuMhw>72!G?m%!sx@sBsc7AJTSPA&TJ~v^)OUzBbRaIXs}m8{Y6XszQB+6t1cfM
z;5I(_<7iPK0Ig(i1B@J;|DwGn*iVov-=IXG_I4z^LGiUxxw=Rk<`kFb@~CSv6s#nN
zuxVc^;O((lN=Ezu`F@}@%s51f-mBl${+7wn6(#DOw>ZZgsain=+v$wo#v=yBqil17
z$^k%WjtXNLa?drU`(4UklR0SMFwL7omb+>k7pWZt^y}uQw$1@tGYFXeuQve}+C21N
z7tuh=V9e4R><NS+$J%S-Qr9G%L6*DMuZ2p?Y;E+}v@nFL<B@#(P0Gh5PbxGN&UkXG
zpT3Yo6qZL7=nOent8AdA&*pid-QrZEXu+q1vOR%d_<2U{Io=FIUOx+4%3{dwwtRT7
zZ_y%=R1BuYzevmtBhWd2^T&CApE@U<D}LiXNFK19F&dnwPZJlis_40Zx?P0PJB2wG
z+7fek6}|7zewNjIqxp?DaX>loFW+jE{a|4$J%sXVt4-R2;+1Vs1p*J@!?(nCOObl(
zL=gh5OLmrJ935<nli_2QtvU^|#H^Rw+PhI_U4Y7Q2aT((J{~8+2W83=9L!koh26&l
z*L%YVKe!=k4dfa|tyhP{YwuuVVGTbs<>lpNO#o1+DeN<J1DpWQ0qIHD{STgVdDi}i
z=A=ZuhlO3%eQR+JCb<qq#8L|X14aq=(q?XS@qbC1HKuPsqNNO;_X*@+$smRTD(98v
zAJu~Je|b>8MCe7h2msaj=Egv6-|?9#F@G-_Rhp$L$0H7oS(4tb53i0J94nzaxS0=<
zY)*zNleeT5Vgbgp7h(99@e~LDU`sKsb9w8UI1q!j)ji!F0sQ=BxYLdp>b>J?Io!um
zvccuXRqrB3bxy-kmM1j9!(T@7C})UG%bZe&z|ynY>B#;S-Hxw=r@>X7duqBoA2}A5
zQpq3W3YK(V$Pf=r{PJ`Fq?ozXy|DF`-4Jk+SwZD)a~?jfW>>}-iYga@SOOZ;s9Q}&
zO-4pz*01K1B#M)`NRDU&-|jRF?0iVZ#<nmqH;Yi2aLF~LVsO_!GNKT)<rl7dS-l?i
zmsBEFhPV3)!z;>@E#jp8zQynNywsnEWIub8MuW$0p$_l)>3YYb_Bx4G*UuOh7*C9~
z_pbB>esZ`$Cj*1sfh_=rL*K5xa<H)HQ55*<LjV7+nMyVN%R8R4CcT;T>f7<4F;e2~
z)<QY%rw#-%NlTPjf(1NO8k-CJ_B)NB|CMnrv0*Tt)Cdx0IdGk=DhdB3k1l=dkAU#x
zBuTrl^kwyW<cF*q0l5SbYe~4++E#Gl>eX$pPtX~%pz5Vnn4EL}+$KrH@CwyB!BB9y
zh~ZTbBdkq<?WbipsjKzoR34VKo9VYSC%0?R#1}F!xIX#*1f$m3DU1CeLynp%%fz7p
zFs-MHE=2-|XkYFQ(2R~y+#gd*-hN;EG%sQe{!LJUU%r{5d)C02S$%XV(`13%n%TmP
zIi)=`0zW7I(awr5VsW+FG~buKOmy)nTF4%}*hR?WLp6_DujV%+_&H%)gjO4`6kKFr
z`GRm?)0WFhtT<xwsNSEO?wHYO8&7)xGJXA;hs`m>ZD!Yp{C8>coKmD)y%mWASfjg-
z5yiqK$3!L+&|)d!3J}PcE?i=lx^hL=R-c1rnck87RN=l+5Cxmotm6xE9^%YG(MU`7
zI8Di|r;;R!6Sz<)YV?UDP*k=QTX^mnm(KhH(D6y;+{4W&Gwe_#-hhDEv{+jmB`wqd
ze7#B<)M|pdHFed)`b%y;(;AFuoZNnsY!j#d%MpSrw+tC^I5X8<O`du0Jfj|ZDG>!C
z`wR6VLTdg-y>M4+az=Xm&f`c1yzO`3_x1xtb6&erH{FK$TaBFU{HH$*d(waf2A%rn
z?;n}IrBB|%t)kI?T0W1*Sz0uY1rCLf)5FOVh8-nd&q}UzpJ`kB6)}AP@X!T|(2GZV
zH)_&4%7n_u3#`OAS!nOqxSjaTJO)^#E|G$&u_kxzEewXAfClr6RNWF%ebtZ3X0qxS
z3{k$V;9z0ta{f2l=XWd+P)SM7-p+vYGyBs9+^vq9znhk+9<tz+f8b*q=x=<?P+@_~
zzyoFwAOnkhq8JKEIUw-h74LH_tYLJx@Kcz~q7sMX{(lsKGs-dT`Ki(42A}ivBSh%r
zYC`rD<xw|>%<w3DnCBV40l9<}Of6aDq}>|3VwO>sMOxcmb_<kGv9NT#;6W=M-NA_I
zIl<qa2?JTR+5K`_gJTWxu8li0T&cs)o6pKphdCtH;x%|%?mXb=*T`^t(Rm-X;zR#6
zHwvtKXrAS4SW1?Foi0jYF<nzEv><LjRG%&T^_ttz6>+8zspB(K@{fhr*sbt%4Fd_z
zx+=kt8HR)}^z(Wc52aBE;SZ6oK4xwlh}~cJo5GPW&w51>rewU-kL9&M@zmrF))_<#
zV`;tP&!0%s+5cL40a7|$-D?u!3XHQnT|x(;+ohVy246Ju-La#WUAnI2{ASf(b+kP(
zqy~exumR6foH^`b;6B#Pmmd;XfpD?=>E;cJFC1;Kg99HRA3q)kf(Yw>f(Uv4GSw;V
zILYANxuezC2En3;rjV&w2r5M!nxV9g3SzuRkg$%*vi9kisaWgsyyC*uVWb_e64XRX
zLJi+Zml^QA`3h<6<Ouy!QC{G^Z9-@7a7$%D0NkRO{LSU~61g@;cU~aR0HjamA90$?
zt1N3t9?J%BP&N;{^6w$PfLVh|UDMu7KImbRbdPxmdVBBdpnwj%CTGZ7$Sz1*@|=gB
z9hUcfZNbxBw)v_`g0n9hM{40Y>C{s8YbBmbp1QN<sf{EV9l7c_O4I=9lM@)7Q;1uL
z<S`w?3jb_;%EqB1utoy&ZyEAye|#NlqBsA_FvKJ&!+U%^l5+WLW6Knq@nn<p(;1^-
z#?CO`)Dwh+fh?>*yKJ>&Q(_zt1{(EP0i!c;S_R>Ye*#MUb!y`Py<w<1h_Y_?lR$V!
z*b3y5J~Vf}u(-H-Yfob%deNHdU_rNrPXY3!PUnfFbHv^8ehKvJgxqr4#P?5>NZR03
zr!}JxKl<`A(j7gXc!hr`UVPa0TaMbwS^ND_En6KO9gSFl5eRn@RIFh!)&$v^B#ox9
zjILww0^F{>i6x*Z>K;M?o3<z|%@Q0%k789(&edmn7jKo!8=%w)-d8UW4k|86{D{pz
zy5t68R(N>%Nm`13jcYB8nC-@MK%m*~HA@;l2^Q9HRV%!N3j?v{g#j+8_Kr2dwF~1v
zmhRu-$pqt%%CbcsO4&egaAIDSa`-ess{^7)`;x@c6?$~>14i=-AW2kz<%#@9`&oQ~
z8VXD~Yi66&?roXm6`a|j@nUf?2n3=FH2w0bEH3im_j>}L10K*SK1IvZfw7t*)ii0k
za{Y+wkICG5VJed{_s&cw>=GfEX>z*_47xW~E@@ZmrL|C&NbsKl@B>d-W7$hfMqK{@
zh8`Y$X^HBM-zXQnW=A4B19KdIm{gagCrhWblS5@Pp43h~=mVDOcXEN22!)ggAi1Xd
zmi}!adG2StLg4$-o{RM_WRZYH9ws^s_d`5~06!!Qm5GFygDS}O<@3UxWi1GBMopd6
zd^q>3_+L363{s2j=dr(?$KF^mYIos+{%-uJ5iisJ$pRF)8y%sDGO~ey246lBD7Lz(
z{Nj_*h^q+;XvmQ^;9AkA3sa{UlPMQ)K5oM{u<;*La?eWK9}}=Y`TpTt+DmV+n1pOi
z%ukSPPkewXb@y6PeK7QxE&_Z}svOz_^d2i%%`RSVM}6B5skMUoeIUd$rl?|JEk5}i
zej$Na(0z}ay5?KypBbJTju)Ghg+Pi1F*fIPWKMmINfHE^{#4xr59&y)rxJt$9>(u0
z_@^D=p5c?>L<h5-px|1zeR8m%Q+qLh^V1@B`u;fo)xb2rC-$^ummi_>uWOwoZgj@=
z8^l}`3}1qI!|uBj8GUX1gd2;h(ttx59^4e>4+M>004VBSpUA-i=EVnIe|szU7gb03
z^AvQae?48?W<_^9a3k?*$JS>S_7u8Nbk)h#JPdmZg~|s29cUl@tC>k)(4|SN<!XKp
zcr~1V@L$>)wv+f<r?&1SNWfyl2^7!5H=lX0Y2eR6Hx8Fb_@En9SJF2dEkaE3zLAkj
zqDLD6%Y5g{IBv#W$e=crB~nimed{~9Yf`22@shV9cXx!>KX2sNt1m(?hqq*|zy0JQ
zycOJ9yj+f2!+$UutkC@I_Pa~i=E?kmH3D!wk%0nGx;-)d@cBYwVMGCEoz&}G-<$9*
z*X2(8yv@be=jP3?r<v!Wmr94HK4<}p2>Zk*nQ2}JDSJL>t)xPae9q-Ov%PWe;!5W3
z*5X2~Z=amUbP(U}^PO8<*)o%0_@JCi-_R6$pO74&jFNZg-%VpSe`4~kHfZ!?5{&dY
z70W7~RM7YEcI3MloqS<p3?!+LfH%d{tSlrQ@3ShwZ*w~gKk1VadY^L)&@VpGwm^NP
z7Pp%M{he#}{ke_(or98nhStL(Tf|nr#qx9~;$O2hCseyAHA0V(4M4uP2Z?n)N3ga?
zq3h<`%Lbow9||AcNmzi;%xx0)i|dWkEs5F1>z_9RHTCGgECed>^m^iz0-uXq#M_O@
zyF-Ns*I1xmNi{9H*C!h1yL_!JySuIYLADFGr!`$SLb!|ho8#QF4oQo7G5DlKKS(iJ
zGAG-&+`S6+I)v_EXDwGGApPs3yUOdOvjf<r9opSFQ_HO(?(Knov;E{C@U+VNv<=IG
z-5v9FQQ8A+pJQ^{&0Nxap-V;F8=vE0A58wq7V3wfMO>j{PcRB1RZ~~D(fQS)#q*rH
zfi$&+%TGd`3MU9x68<0bk@i3jjBm-2g|2T`h2lKW6#`m<7gbqVRvec}seLYIaBd^u
z+m_lOjt&n;_89T<@@_d%Kp^-%My%$xdI;w`wmw%?C0<3w#7&=1M3wGRr-U#M__QDz
zqkG<G4Yr;u#Gt>7y9{l|Ggc~ahG7DHHQ89dG^wKUw++ABxM~Uu0J5SO0Jh)U?7FmA
z9u3~zHg(;doypq(>xJWYK*4b2ro90QqF(j32ADepz8qIdsl?-=dyKZ69%*3jH3N^p
zb);m*$?TJ9IUsS8uXW0ue5sg{j7_8?_*1_RFg`)5l<(pit1SwE?1@TFI|d2^)kmg<
zl(_z?$w3Yi-gUYV+cC^3=Y`0)W{HBH-i`*$Q}U{#RAm+=u0-ne0bY3_X{R!|tDp66
zDpah~hilus$iZNXPq{dO#WB`S+IOQcVa5W-{@mz#c8z<9*UkZ`LJ!ga^&k*yQYdMd
zVe=9DlY1Mm=I$tT6K()H3+~OMtci7;&F6Rho>Nc|rn4PZcJ|74O)X12`#QnmVgC)C
zo@>`^5ekLQ0NXi?iStqcvL9s>6rmz=8U8W38^L1C_L^V-B+RlDCEA?$5L6m>*)Pe^
z9~D_Ah4v>vyBZw<AJ7p4MiVCBQU2I}MET1EtB=A^kGx#G*>oEYWlPJEb&VG|iJUWu
zq;6ht+Gv?(j(a`r_*^ol!LeL&%zFBD=~DsYw}DhuzSLs7qh??@22p_;dpK0lK~eEp
z>{0?onrpGF+*%yoN)+B|5GAg@;DYlGodYLX?&lX0Xu`rO&xOs!yz7-6Wf6U039P1~
z=3?HLZ-)8I4{T^+(^t7}`CzDK6&QAZ`HD0!sVfhyb_65N0*8sv_jesYryw}~gRElj
zir24F5Uc^cY<iG~3W%<GCw{1~XZ^`SnlD7DnTiiORY%EITR8zJI9pJl-{pKQ=0;@R
zup;GP@}c8*q6yrJTRY^@unR#lLcCX9I06U*ACs{y%sADrURP>NYjf1=jW)04>fA}G
zah6t9hbEl@J#yTC>FfNJJqQA*{Y)1v{2CKs$k8>k1$0(h#6RY*1V)3mATXSR(Lw!4
z&II}xpA7W^hmb&Hd5gK9xw5v-U%+-cX<-uGK!U<OFN|gA5+Q<aHQ;g}v@FH8UtV?n
zftD9n|FV~f^&Gmuml^J~Rm?9vzNI=CPW7LgdtKUCUr$Tgmdg#STjKNC+gI*z=FX=k
z|56PNghF{cM+5&Yi(A+1ZPmh#v7K%Ban&b;aAj7`W!6!l>+>a>_qb6G8$5zrf@sVc
z1$qmsA=0og<Xemfz1Nhi-cb^=rQ@L-bLO&G2ErO7j6QVqdTE$^>q0aezmawZ28i&I
z7}klFZQoA}@Ki;?FA%}MOu>K1V@|ZxI?**1x8;fDPks{a^Cp1Q71j@~J4K6O+?Ndq
z%|BB|F}A8xzyNXr-Iw$k+X$fJ6Y>)x=E)BK{<==&e~Q|f9~y286NX{6iY>%veYWGB
zw7gBwOF#QaX^f8FmRtioRWT!d{tgOTNuk*mLeLSQQ(<9!tp>DIW48-1Eje@T7#Mco
zDqS-*HKPna^hz88aeRC)gxgJ@4jUV?Cb;5Xjbhu(D+y_wOxl!vTI?;UvfS5@Ea9-0
zTu)5;76)e*gL_r3N`|Q}3k#d{ID9fI1r5}bgm-L`5DmY-*o92*zx=@^V8R;omv6}3
z+z}6q6?^R)Cc7*w*!8C^2b$)Z&kX}rRn?J5psPHYo<8h#-StcBnhxTKbRhKUzPF*8
zeS04EzF>XGBaPi>Qvb#d27?1+?ho0JZnE3enA5(yC4^NU*X$;@?4rB$lb6|hGrWSE
z_iUVqjU|Jq&PU;gSIHOin``Pd>}mbtRRmm&X5ZguMZ)jan)rSc@qJH2l6(N0QT1*l
zpQ~TFniUzE5CMKYj)09N<D1UuqVFC5+XtXkp@W-?4C+g?oq>X)mId$gHU;}`pSlO2
zt?-t!{RW?sCO3{d>il0tEmNVlA|6K;LO}sS*A#I>JBX<pOqE<MnnXLB1^}ztz+O3O
zhkh%+TjUh)+PTE6^HEqHp3px*D!pqa)(2h8F-9cc=wY|&BZ0hc-ypYcpM8D<YTc;S
zQ`5%2`Y;x!O>kM-LXGw^<vmQkL=?#SS%fAKD2Xlo3idDga5MY*MFz)-qw_3IO3m7B
z8pWJU%XP!mmOjRycg}4)<;-mq%5I?k?R-|%+{$kumTwjpbBuF1*V1qHHflc4tJgHJ
zrJUy)tc6*RJ(%0y-S{DRlu4069Gr_2`07yKW>X&t33S~PUUTbywM06HWpg98T5{*T
zQgTUWif_GKixQk9gi<Kvir3L5l;=%HA9uqQa!bv3{6*^`9e6+omXd&=LI@+R;FGN<
z=VU1+^Z9{+KCdin^~QIFn$+$O*fLIgp7y$aRhCMnL^QpkHm|WK>-XFK_6=+UD(8p&
z?e1cCuvc^SZFjNGC|r$v^`%4CG@Dc_CA=EL4{pzTjaUyn3?Pu-Kkn#uSZ!Qg9N(o~
zC}9t)sq)x3-1?lX13?=`|I_tn;fanoe||r3!^Gg<yYR(JuFvkw@2pq+T_o^N6G$ns
zu>M=aK5s2$(Y1SPXX)?%3R>t$Wn@~KNYM*`uj$9?!15hDl)%HVUOe9}@zRNqtC8=V
zfCZdUyaW^vTBoSGZYTO4hM;E1Mv$_Pr$nvV(eEY&dxqJ{dhhbIyDV1w{olVatBd9q
zZ;dGL@VfR;|MJ!+W6z^BW|-~*P$KS@Vouj%s&A3B`<xf6s+zq+((WMVM?Tt@YjisU
zbUUOk#BQ&d7S+p-kJ6qD8nj+IKine${!Fg(^1-Xy(c6yYKj)xiyLu~tde$VJqsCyg
zS*Nn}3(eJg@iDIYLV;?H^7neq7}C8*HM{4x)gWATL9JuRZ|W1|O$G15ri%tC%cEa%
zBu8oIHZcy>*VN6YqYv&*anigGhVVah43p-DSvprI>M6kQlj(QcHTcE2zYq0HaW`DQ
zgort^uc@1b^p7DvWd|BJTj6^lxBF37uxh3n-#fHFHCNQ&tGYj-zb)?b^+wHS*Y?hS
zKOk-Hj(8iWInLY1bbDU5=)$+ZE#Wm|le7LkiBId!$l$oeI{~RM{}<`C2E>Quj#_TC
zXch#y)xW;mp4XMsp1u^?x4m8EtqDVyg34PGzEZaOS{JeXJt8yz^C$A`Yc0P_v3zn?
zQ7Z>>=r1{~w&xUG8LF6Oe3Ev(FEyP+jGXtue)+g%Pppfi!RDRXC0yq%Q+zD8&6avC
zq>YlNdX_s?E(ZN86{lLn4YLm+R7ti2w?{jk+UGwF`~o5gu!aM7c6PF@l=4+Ki8mYf
zKblJ56|?C}XCzNuKKIS;p%Fs$I{4bRnDgLmqd}*>Fn8s{b9b8y&@mz?Hf|2&Zj<i;
z0>x7C6mT+{efX7o1EPO9<gB=o@Jih?V7dr;ennEVwke*3*LNo;pu=7H@aVi{?L+jt
z>}9Nu$Cwh-*g%;+E9+j@r>*(mHTMMRQP?SR;awqH_xF*29rSQQav3nFtwudQ=Ko>s
zEyLQ{+I8XJZE+}89Ev*>cL+}L;!bgg;9gt`6sI^8D^|R?OL2z=D-v9T`?*5b+WX!6
zobTVqFJd#voMSxWwr7O6^U{%}MK>?ChsQM;Zi4tb_6`Xqyb3b<B?{NOY(s2zLykLd
z2OVisagEzG2_xUrw=2*Dy-H8dYWQB+XNp-85h{8ES?mM=+#ViR#J0J!bX^CQ?`+!N
z6O*@CVSOzp)YC>j_sH>@@Unl}s+^dU(QfCK7<2yB75D36t<-HZR<}TXI2buxF`Zbs
z;zjT&BVZtdU`W^^oJ0wG=iZtY1geHF052|XbOMGX^_{j}&%DXH4yPC8LEXx{EZjT^
zemCsdRZERJpUy^;%<MnQ0NlPdP$*R6p!+++lk8*uk#uT4fBDB)Z{WcBOJaw3r2lcZ
ze)s?VJ`wbbg#S=xb7Ja$%7vZ!b~D2B(+XuPCLztJNecfQ)I|)uJmyBQ^Kp#Vb883q
z&(qD`{{Q&i{~Sz1Kr<`04+{&5QF2&uCmP!~@q5uQUByRJYCOdAvgpTNU2y}oH!^L(
z_5>)~`0s0y$Tey0R<ck<dRw^9+z@`?t<;GSrnF8&$HVyfnqB&fw6eO0)s#Q0k{j~b
zssn8FS1>58hsU;3+Vk%ZShi9B`G81r=XC;Y(L6q7U@`@KDM<01-g*;Th6l=|)MD<A
z&&sy`@83%j^$pB(Q+qqE8V2%;Nxx=2Xh{*2#sk439O(;6Q$a~1$va*K7n10JV9gGE
zxmY@Ns*#<1mXuGp!qu^bZh{aop5r^^i8pMU5?f&c^Q6xSct$tMV=>6tdq7}`KgNFW
znwQUSY_}h^O-NVxJgw7VJNbu=vzKIiEuUD-rq3XqLm{_~vzOV9De&GM9x9#Rr$y+%
zf@FHZETU))sZ|0fYh-qA17H_4#l}=>P_14<Tnnekoon&(<5ls+DEHZq&AxADta(|)
zs0LpKR(8GUsc{O)nC;S=G3B*q-ACqWg;?0C3<DaG2=k+rCwLv77Oj<c-A6S&Yrz`G
z<^ALIo1`W0cv_SKKA&Oyy?Xg1Tni{Pf<HJ-qTi8HBPTvQyu9LBLJzwROZKqEY&LM=
z1IgJU1=hG<p%=H!njR*$l6HPqk4?>=tRMd6250P6XUj*)voCi30EYOCAD9CYz&hza
z#6XKug(Vlr`IFpcO-s7;I3nM-S2YYU9Hl*Y!h>1-g0<6S_b<n`G^J)Se_0}GU#yZG
z54}c?ReJk;PQ{pxO;xAIHcy6a)X@P(*T=mql*fUicb|s^S<+WZh0E?vr{*Kr@cH^e
zTdU@i1P5+ON=lkTCUV5ns)&=SKfOEzL|&!I33Fe+5ocBezbb%it#y6W33Wc3c66=X
zI=XcE=0SXYhpTuI*^(cPnM3~DF33dbd4SW4ev4Tb)S$;{cyl_jvWHNP8MbW;_wMr(
zxVQn~l%;-j_EO}+6@a&4MtXfaw(Ya~?!AXhx2B)Ed@%BzzsbJ223$4eC%KmX0RffA
z_rq0Cb+2LL797rGxU$lo*IKkQu+jW}y&5smm?&gb4;fHzy=>^U&9mY}a||CcAob1w
z1u(m^k}Y2dUR)e@Q;tX|(O|Up5S(wLXSeyRbT64io`K}5bf@NWE&kQK_0R7wq5C7L
z3G#ElJN6>7=a8oB_7}b^_C>LR{h4x(OJ91SNY@A7OqHFv$FA0EFyj4NdNXH{awgJ5
z;goMKQYt*whk7MJ1h$0kM|=Wbo@?fxnV+rPGO0t^HSQiLfFP5F>i<`@D!`45iaKeF
z-)F^wS@e^Hk*beswxFgXiM6$*$mfX}^o0<@;H9<^NI2*wlhDhhbQ%cLEFyMZd*=K{
zy%AvLr=(@;9$c(`evp|@;0sh&Wc46v+>cryLB4RvjbQBi3#GN0&C^97P-B8H5<4p}
z6N{P=!&j7me#`<0)F2^@#3of(4_GZ+wy&2iRx7=Bw5A%0ytb289K*%NV_o^rFA&S*
zOivK*27CWW9VZag<fOcpDS#?Jx_?}oit&9+Z-i1@V-&XPWXlewfPa+Quk|O2hyvWm
zSQ<Y*DinGg)yc)@KlM_L`yp8%=qL>)I_CEbS~Kwzn!SpS*lA^_lLjFs%e%?mMnBQf
z=HqnT6Jk%^n7)+;d6VSI0t>@V39%==Okj18fa;x_QN<+9Jz6BeRQVVW9)Da|9PQ=)
z%qUmh0SR*lp1x2~es|J7FUDlwx}Pa9T$NPd9d=+{OT{``6foV+52F(b+PE-403c?4
z6;v*Iq^YwW&-=ZiH5I>0((EbGJ<*W#P_R|q-5d~8K=>+Fw_w<fAc7U&)f6Zrdvok_
zt6V84o0LP95dgPJga)mJ(D071eB$9KfaoJ*fowoyr9>Ih#SYmoSuhWuTrN=H3IlZu
z)NPNH!^}pDUW_j!%~2(e%7f((=1JXiXDouwC5s&*6?q1rj(07ad#7_XUkiqDky6PE
z;Bl}Jpvskk5+KSnTxtQu+W@b0IBJ3H6FSj99R*~n*@7!}jr-U*`cswofeTf&_hg`1
zxWK!Bg@t7v3eMm6gL__rY}=#VU$8zEd=<3KZdA+QdFR#vEl$6k4@<Iu)Gcz2>qFSM
zKI^$=t^V4r8JseTSGP3n7=sQgdSp?qiHTd<)Ve8j#L$onBs9?6|BBnoseduP;K0<<
z>z@TFPQMK>L;vBuGS+BPb2DeBS>@VJUw%)hn*Ha=Re=OnGMfQw6L0=_*0K!fI_qsT
zGMb4e%@)XbdZBNf1`JaZ)*p&`xUIAo9>E!tJ)PwH-E=qrgrWGIQy`UEtGmfb*8!-3
z-HfTH*Bs`+I4z)`$>N^oiq1V3QaEEVjfwuv;U!yD*ODnf!pL_A+Gu@6jOlmUCB$kK
zl#5f5%-C-R9H4uOW#34p3pqwQ#pD=9fxwpZW<VaBNLm@%uf?JxJ?ZBAmc^;?V$ED|
ziPTOsrWVtAHICcE)KNp-o%<3_8Xh&fuWhK;eNRJO3(KK{Le=pbPHt4htglZRZC*B{
zH*uUZ?B{(1i`-z`ACI+T@t(Qo7Sotn?KGuj<h(sEKO@9@gi6{HHEX%>8Geb_;e(C*
z{4)aZZA32?D!>@)Yq{sg$rw1m2n%vZZ`_Y}L~w%}c(?;34c0*|<3g^<^PnsMplth)
z%NG$otC|H+j$b=Y?$r9*p-NKfn0i>5>!Rw|bf22p;99D<z2Y6-SFkA7dFiOgqc0O=
zVmIrzV_xOzYFX{ztdEggWQ&B6@6TJln{owBQ-3tYFW9PNxa|brU=<)0QkN$GScNA_
z9vK_i!KOhHn@La?FGZW-=;oiAaf4S&aoX}phkd(_jV^wXGFs{(j7=BmR<l^*Z2+)@
zyV=fPx>SP^wj||K;XZDLZ;<y9h2gPc=)BFpPwIJ^af0~`ctnZOzvF!S7=$C}9nAy2
zXiJ-huRR^o7fgAXo%rBj8zA<Z0fB#(B4xk@u4?ZHYORzuWt$!$)cI6&0W+_MJo|d3
ze$Bqg(&c(fR+Ya{RnCJ!@s9f)krLSD)#;wK!O+V0bxR?n{QEDQ?^Knd%@21*VDL+I
z>;O;J-)`Sk%usp>01z+U8cQq<cxf+FMM{TeuK+E8<PDKsd*C)?f<2HCDEu)7hf{N^
ztJV3!)hVd9VC9>B8!94-|NCAcG63M^?Bp7q+Xq!)CU-N^8FmPWR$3-Uq)HqWSkyoq
zmfTx3>r5*Qkp7*Zp<PJ^Dx&#`gKIQqUPw2`<Xx!1(9PALUH!{~#-8SKKSA$>0Jp&Q
zOw4;~f(Y{STy?(dZ?PV)fFP`AoR&lY<s(B4fFe+PBoS_0rfrNyyN@h5#OVk-7B1Td
zIOd)er(;nicF^m6TedG%CzrTRB%hUL*?Z)62%0_9e8Wkv*KIx9lgHh;=f!l`PTJTT
z%lvb5?!L|Gi454<mBjkXB>C}(EAIEha10;h;QlE2{I*gYW5L^qf#p6QjREw8Iqu$A
zI3K1un#Db?XYJwB6O5p=_9szbivbH#7E?=W;TlNw42*`TZwTW;C2a#YMjLQGA2_t^
zZHBhCkTqJv5mpVB8CWj{96>LZ)LeiQZ@Tli)5_2m;&RvZrpm(GuQxRo{eOm5I5%-;
znIq0I-9GGD8zdO6as$E|$Vne%QpQCY3-Eh}YpbP5lL|s4ZQ0|V?keG2Trge2nS9{W
zmDl1E1y&faCdFY3q-x~zdI~=ogmX+TIp#>2h=3+}8ylBl^5XW7m2&5vGZA3sLZRgW
z3SF-?{kDAF7hV>3F%;PEOyk{jtBn~lRTcnOskxJET-p~nG2=HZn;Ot)^kRIWQusTM
z%~ctj<$>Bn>5cMiM)BO@Q~JTX`h7@G-W!0a%*zKYYq-EQJ*E*Ba>KfPT(B&ED9>RK
zom-4L#gN|3k3WLc98~!@$!8s6AORXYi2;NkOG>-g;M)>J!pObbhc<y>ZUef&6)m+4
z&4YOzX;U8-WnOSyUMZ|3B)<<D%dud5Bw9?+^y_e9UgCW5UQ?*XsvjU0JK7u9Ijfxt
zpXK5P2%I&&yg`WNT|9Iv+41{$V_o!kVPNMMQi$5IGt<cBCKqs(Zdu7W7cqNwdAhB~
zQ0%lIN4oJk;+5(gKEC=d1OU{lA)jPDnO{cAl_Po!7^@**srwbW77zpy_)j>MU|$?N
zAb){Qo^IDZdt>0Rr6ts&=3l0cPx4ruJGaAns~0a{2wQo9Kn+6ZDSk~W{^RQwxtItX
z(wo)vgOSCqNf_MGkbPzTvPQ_*CE1iVen%T>@{RX-G%*Ur3`FeAOo_g8aZyM9dzVJc
zKtzetGu6uP?)Qv|c!f>Pk&mkN(<6mIe*C5{I-(PHCptApz8(Fq--)$v$&Y^0<llF}
z?nR>Jpknld<Dd}z^N9=i)=Wqmc*9mjUF}Oql#J;YpLL2UCz2^EaxUKAF$4q_QgD!&
zJ!VEg-y6!9{z<D$bG^Ciie}g#H>1i=pkhNF75#)19#B=f1Mzt)?MxEj7VF6Y`^i1}
z#z&({!M}cyhRgpq@dGB=XI2NpfSbJTBXgZ3P3T`LnJiH0s<Q4<V*@Wkhm-s%SG~ZM
zmCo+P_`<s@x*h<<B@?C+Z5|TrND>4vTrd|qC>vAqcK3MfxZP?VVOTQdi@pcUKQ1|E
z$DwAFlb2@Vycs6M+G%wU;6$r7DxTY!d6U&F`T{U4Iix-sACaq$ySONXJLGl+`}nU6
zN~KNLi1hAl3#E&dh<>^W6_ZSVm`Dk~teS<!>vFxdU@p>MS-6n%`nuK0<TXgS<7>4T
za0EZHL2ft`ebxE%#OL2E01LIj<FdW=)#0^~$9e~LEbro!LkA$y)<X}xoFXDrf4iL`
zf0zX`89^)Z+&Bn;v+HnsYpomS*{mP#FXMJyo?J4MB7RRs>u|tRydBGH9QIb}!f8+N
zGT(Ov5Y}3OY(^`TM3*{H-~d~U!D<xGaImyW7z(LOgq>iif+Xr{jl9x3n^8Z#S|I^j
ziyD3tiaF@SBkO2<#B~~LmTp1qdnrJ~Lp6tiRHf~Gj%&d$hTa)fdqCiKCN0059zcT#
z%J(W?;>AqP!NZA3XFy=+<F$D)>c>`7<ju?l7#2WJ$GM7nXdZgvwjboL)^~$3fs%+M
zm$yZ|s(YJ3t}IV0DJvk8&B@{%NRW1%sj5uw?KbSB{4^h#B9HyN3tl-%^Lx_6p!~@W
zKOm}zLRJx>QTGrLQm1XjDDwR<*=#eGBo#hT<(N<h2V0+T*XH$ly*hH!VO*>&COS<6
zE-~p<^><f2upgvzq5GFiyc*S&Jp{eu=?xsaudP(>8Tf%_Ewn>xEYdu}Co}-m^;Du(
zp#F4T2*$bYC5G+o7BN<oG>^*_7vMQrxf(zQA6SOxeKYx(Tb@?gF8}~X9Vaxr0sDi_
z?=7vHtkDhPlm&XLRnnWEn(FEbg?`_Xh#kkl1Jd63tUZ#1Q5;Wd>4-S62DDh*GzjLo
zSnc_n#|a6SG|@QU&B<tgjR_>Ffa~N;(h3<H+5|7V)7Uo&cKGn#z_Hh{pwqlA-A{GL
zCBGWTJ}=gUvD$oGMo8v@+%Nw0!7Za7hH_{ail5tpej9E1wp~cXdZ+k>HQXu-n?cPs
z@VKN?fPfdQF>eh??E5^PpR-D|u6jrryoA<Yb`tO#eiJ)J&WreY4z8;WebHXu>D}->
zKJGpisNd40%NDVn?jHcX52L&<7~aNA8l31QR5z=F4o={c&$|C3eX%9^n{%SML>tLT
zK8YW~=o>a3(SI^ePL)!P1R;5r?UeAD#<kT$0;TFJp%QL^Q%qHVJN%JiE6O-li^{B1
z)9m%DP=Y6ktcS*ecc=C`Kd-Yzk=oZ#Re4tTq%JVz?hU<9S5>2>FGY1fFn(ZIrE?eA
zY{@RqZj`9>c{V|Sq4`NNblE_I4p3(YE}A{tw`F^bLYM-TFO=L&fg5jvm!DJ^1^^~~
z$imSi9QwJ1mG!TBk)QgLLLF;(w+y9_nHw=A)$(EM6mxMZT<cK@H(`#|TkuiKca&0q
z=3ixjmYlZ-OKl!bUN@ehXHR@r0e$ya<jC)1Q_((RAnTKZs0d16pj3fk?&srAmCXrX
zYmPEGaHxln>!nklIj-tUc3<1Rg<`B+8LNG2C+-F_JCi1(l4!d}q<ztg)7fCO7XsWK
zb3%^f0qy2D`@8)|sFI%j?)FNR)bzHWk+Z%Eq7FYSYmIb%P=a$YB#gv1mpmOAObQ@`
z;9z4PPOtiHrI)o<xFP^Z91UL##j@U4s;?q5!`4l)jt;HjkB#0&a`w8+9wwWrg<IIn
z1{hwYlzty;ZZwO@0mfd<swk4ns88G4EFg}zg48g~MH3~?jIFB5S=Sa1=CpGp0lT9g
zihhQ)nC{&cE<Y~d-UKx~T)6wVP?y&4ph1OkHV8spd!yxm&d?f9IF9(l0@PL1Q**sn
zS6DzG(DKXi7s3J1uQ8g4^}ZwyDjF)P{3*40w!^Jv%%rf|1zc=Z&6lgFQ%4OaZ7LJt
z6jW3K1-|2v*w~YO9H?9CBHj+l@evU_STGE$dRe0JJ(`RmD^wB-8#{{>c0q^WtUdG!
z)$nd9VIBPctw)}Uz#dFUat?MGlh0P}2*eNvN=2$Osb6y7P%|P<N-eTyHxZ-VWoTwy
zdVF5NfWvBwmiAe%+*qiJ-N`>2-)HsFSwE`d!5t#EHt)u_{;KQ{9}z*HbNV=ilbWcK
zS%4eq^3l9|Ynfm2;Y}(IK?Q53wf#!guQgdSo0+5)i+iU5mBksHG~Dqi2H2=G9mph9
z4N^<cI6-TfU%O0F5a!M=o?S-(Xy1Ly{u=M`#{|&s*0#DBv}tfR3S1q3<2Zt#ovwlz
z1t39~{w!WNivF;#jmnF^nW+t$<RR(3EyC=C_z)i<Be>I&`ep3{5W~6kFM5o9ymZ?5
zg__~>c!uXgpt}7G=;I#e#`qZGKp@C4N|+AcpzgQc>`T$HWZXtdZvsh_cSq+(nf$e?
zeEHElcOis6wB8s$(<Y@d+PHVWmMfMVA|y_ZR9LjPPD*81a{HM%>z~AXh}k=Sz>I3&
z_S;Lcb#swW&e?#reSZEHk^b6HC54q;^atCU*;Aqn8pm)f1K&>~zXVyl!Uq}+>Dus(
zs3!st#L&V928w8oL05%Yo*8#6Z%L=m6&+r671B$rOzPD7E)kzF(4g_Yx9zIag8g!I
zgy}1G9Kl_J)8Q+g)@ika0k`#lDe`ycOgu$pxhSSt*QQ}P-%w<UqF&CvoCl(XRit7v
zdf$I>lXC8Y10dh!Zf2z*Bkl*A{1Wstyi&Ih<%LWr**jMFwm0GbhBKZGKmb6{$Iq)~
zFE#58lnf71rMhRqoPci3qTiL8^=%hxIdVuz_&7wv=l~T>6OCA=M!?KF-EoLU$qQ#9
z*e`j%Mk0*NS{@1+ZQ0RK`zV+gt6AUn;ZPfm=2*=~6D}g#<mz@<etggWm8{bI^VNL;
zP|<Y6V9OMm)r^lB9XI`z!Z(Slz<-2d4er0@j$~!s$<V`~C+TR7u#8%-LR#U+%}Lop
z5`9_FE`f2lnbQkk+a&djaG;?}A;BZA^X9jZ^y+E#(0$Vq-g!47_a`{6tS)diR9gwn
zh`JrY7K>)B+Y|`Y`1*<gM-Y-$d6AlYSAd(`<<`FaMf$jI^RVX+{cRD=aosAReiZG|
z*Gsd7rW(<6h3mC!Au!{)<qxn1F8Oq5H%Wxs9-IrZ4;S*)0KKVscRrerdS%)OVGC`Z
zDD?+kGr8nC4wt)vKl#y^2(<h@O(qy3_bl+_Z*app@otgEa~n23{{GSH;UaJ0@?c(Q
zhJD#Ju+|=f;Ec}uUS-O>ASdSfoICG`hNU}zn(VDdTlr%LvSj&ah1vPA@v+0p!OtC%
z%yjrsA*4lLCHJ4vVx7d->K<eAqyxGf3cYj<ipUG`#M}e!*;LCFnzRtQFQmOPTq#D5
zzrW%Jg>K(Uvq`Kt*#R}h1t5Khfp6wJ1?w$mF~x4Wmnn}`Di>$~r^6Sc7TS7_0}1;1
zt!wH2V)o?70F4;BhFflU*F?&>#+#jdbO<~JX3(M{Ay6xSh<K|FoncYmkbkDs*{j$9
z0FWH7n@Lp3cXxX1+~byagCu{)PT1>Tw8K&x<{cS`dMO+XZ+aEkG#vP$m=sSK;GP11
zD}AM-lomDgWdnI!q*VIvRBeC7K$k+=zA(YeK~EcS!B)l_P9StVNA~Vzq*=3yH$t_I
z;5}gq-8z@m#gVo*<4siZY(@|2%2m$!{D#R1rP-#FT#G2ZgSmt-i6Xy+oY6`2hq;wv
z1HPVe%9s4rCO3@;Os=(C3!;J%0D#Tsqm!IZe2CcCll+X|GSl)K%pQTY4&@!?bsaIH
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%0DBq^B|3}_1{F7;lAQ#Pv+
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
BZH)i`

diff --git a/pyparsing_py3.py b/pyparsing_py3.py
new file mode 100644
--- /dev/null
+++ b/pyparsing_py3.py
@@ -0,0 +1,3716 @@
+# module pyparsing.py
+#
+# Copyright (c) 2003-2009  Paul T. McGuire
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+#from __future__ import generators
+
+__doc__ = \
+"""
+pyparsing module - Classes and methods to define and execute parsing grammars
+
+The pyparsing module is an alternative approach to creating and executing simple grammars,
+vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
+don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
+provides a library of classes that you use to construct the grammar directly in Python.
+
+Here is a program to parse "Hello, World!" (or any greeting of the form "<salutation>, <addressee>!")::
+
+    from pyparsing_py3 import Word, alphas
+
+    # define grammar of a greeting
+    greet = Word( alphas ) + "," + Word( alphas ) + "!"
+
+    hello = "Hello, World!"
+    print hello, "->", greet.parseString( hello )
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the self-explanatory
+class names, and the use of '+', '|' and '^' operators.
+
+The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an
+object with named attributes.
+
+The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
+ - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
+ - quoted strings
+ - embedded comments
+"""
+
+__version__ = "1.5.2.Py3"
+__versionTime__ = "9 April 2009 12:21"
+__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
+
+import string
+from weakref import ref as wkref
+import copy
+import sys
+import warnings
+import re
+import sre_constants
+#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
+
+__all__ = [
+'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
+'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
+'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
+'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
+'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
+'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
+'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
+'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
+'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
+'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums',
+'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
+'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
+'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
+'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
+'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
+'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
+'indentedBlock', 'originalTextFor',
+]
+
+"""
+Detect if we are running version 3.X and make appropriate changes
+Robert A. Clark
+"""
+_PY3K = sys.version_info[0] > 2
+if _PY3K:
+    _MAX_INT = sys.maxsize
+    basestring = str
+    unichr = chr
+    _ustr = str
+    _str2dict = set
+    alphas = string.ascii_lowercase + string.ascii_uppercase
+else:
+    _MAX_INT = sys.maxint
+
+    def _ustr(obj):
+        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
+           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
+           then < returns the unicode object | encodes it with the default encoding | ... >.
+        """
+        if isinstance(obj,unicode):
+            return obj
+
+        try:
+            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
+            # it won't break any existing code.
+            return str(obj)
+
+        except UnicodeEncodeError:
+            # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
+            # state that "The return value must be a string object". However, does a
+            # unicode object (being a subclass of basestring) count as a "string
+            # object"?
+            # If so, then return a unicode object:
+            return unicode(obj)
+            # Else encode it... but how? There are many choices... :)
+            # Replace unprintables with escape codes?
+            #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
+            # Replace unprintables with question marks?
+            #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
+            # ...
+            
+    def _str2dict(strg):
+        return dict( [(c,0) for c in strg] )
+            
+    alphas = string.lowercase + string.uppercase
+
+
+def _xml_escape(data):
+    """Escape &, <, >, ", ', etc. in a string of data."""
+
+    # ampersand must be replaced first
+    from_symbols = '&><"\''
+    to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
+    for from_,to_ in zip(from_symbols, to_symbols):
+        data = data.replace(from_, to_)
+    return data
+
+class _Constants(object):
+    pass
+
+nums       = string.digits
+hexnums    = nums + "ABCDEFabcdef"
+alphanums  = alphas + nums
+_bslash    = chr(92)
+printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
+
+class ParseBaseException(Exception):
+    """base exception class for all parsing runtime exceptions"""
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, pstr, loc=0, msg=None, elem=None ):
+        self.loc = loc
+        if msg is None:
+            self.msg = pstr
+            self.pstr = ""
+        else:
+            self.msg = msg
+            self.pstr = pstr
+        self.parserElement = elem
+
+    def __getattr__( self, aname ):
+        """supported attributes by name are:
+            - lineno - returns the line number of the exception text
+            - col - returns the column number of the exception text
+            - line - returns the line containing the exception text
+        """
+        if( aname == "lineno" ):
+            return lineno( self.loc, self.pstr )
+        elif( aname in ("col", "column") ):
+            return col( self.loc, self.pstr )
+        elif( aname == "line" ):
+            return line( self.loc, self.pstr )
+        else:
+            raise AttributeError(aname)
+
+    def __str__( self ):
+        return "%s (at char %d), (line:%d, col:%d)" % \
+                ( self.msg, self.loc, self.lineno, self.column )
+    def __repr__( self ):
+        return _ustr(self)
+    def markInputline( self, markerString = ">!<" ):
+        """Extracts the exception line from the input string, and marks
+           the location of the exception with a special symbol.
+        """
+        line_str = self.line
+        line_column = self.column - 1
+        if markerString:
+            line_str = "".join( [line_str[:line_column],
+                                markerString, line_str[line_column:]])
+        return line_str.strip()
+    def __dir__(self):
+        return "loc msg pstr parserElement lineno col line " \
+               "markInputLine __str__ __repr__".split()
+
+class ParseException(ParseBaseException):
+    """exception thrown when parse expressions don't match class;
+       supported attributes by name are:
+        - lineno - returns the line number of the exception text
+        - col - returns the column number of the exception text
+        - line - returns the line containing the exception text
+    """
+    pass
+
+class ParseFatalException(ParseBaseException):
+    """user-throwable exception thrown when inconsistent parse content
+       is found; stops all parsing immediately"""
+    pass
+
+class ParseSyntaxException(ParseFatalException):
+    """just like ParseFatalException, but thrown internally when an
+       ErrorStop indicates that parsing is to stop immediately because
+       an unbacktrackable syntax error has been found"""
+    def __init__(self, pe):
+        super(ParseSyntaxException, self).__init__(
+                                    pe.pstr, pe.loc, pe.msg, pe.parserElement)
+
+#~ class ReparseException(ParseBaseException):
+    #~ """Experimental class - parse actions can raise this exception to cause
+       #~ pyparsing to reparse the input string:
+        #~ - with a modified input string, and/or
+        #~ - with a modified start location
+       #~ Set the values of the ReparseException in the constructor, and raise the
+       #~ exception in a parse action to cause pyparsing to use the new string/location.
+       #~ Setting the values as None causes no change to be made.
+       #~ """
+    #~ def __init_( self, newstring, restartLoc ):
+        #~ self.newParseText = newstring
+        #~ self.reparseLoc = restartLoc
+
+class RecursiveGrammarException(Exception):
+    """exception thrown by validate() if the grammar could be improperly recursive"""
+    def __init__( self, parseElementList ):
+        self.parseElementTrace = parseElementList
+
+    def __str__( self ):
+        return "RecursiveGrammarException: %s" % self.parseElementTrace
+
+class _ParseResultsWithOffset(object):
+    def __init__(self,p1,p2):
+        self.tup = (p1,p2)
+    def __getitem__(self,i):
+        return self.tup[i]
+    def __repr__(self):
+        return repr(self.tup)
+    def setOffset(self,i):
+        self.tup = (self.tup[0],i)
+
+class ParseResults(object):
+    """Structured parse results, to provide multiple means of access to the parsed data:
+       - as a list (len(results))
+       - by list index (results[0], results[1], etc.)
+       - by attribute (results.<resultsName>)
+       """
+    __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
+    def __new__(cls, toklist, name=None, asList=True, modal=True ):
+        if isinstance(toklist, cls):
+            return toklist
+        retobj = object.__new__(cls)
+        retobj.__doinit = True
+        return retobj
+
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, toklist, name=None, asList=True, modal=True ):
+        if self.__doinit:
+            self.__doinit = False
+            self.__name = None
+            self.__parent = None
+            self.__accumNames = {}
+            if isinstance(toklist, list):
+                self.__toklist = toklist[:]
+            else:
+                self.__toklist = [toklist]
+            self.__tokdict = dict()
+
+        if name:
+            if not modal:
+                self.__accumNames[name] = 0
+            if isinstance(name,int):
+                name = _ustr(name) # will always return a str, but use _ustr for consistency
+            self.__name = name
+            if not toklist in (None,'',[]):
+                if isinstance(toklist,basestring):
+                    toklist = [ toklist ]
+                if asList:
+                    if isinstance(toklist,ParseResults):
+                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
+                    else:
+                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
+                    self[name].__name = name
+                else:
+                    try:
+                        self[name] = toklist[0]
+                    except (KeyError,TypeError,IndexError):
+                        self[name] = toklist
+
+    def __getitem__( self, i ):
+        if isinstance( i, (int,slice) ):
+            return self.__toklist[i]
+        else:
+            if i not in self.__accumNames:
+                return self.__tokdict[i][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[i] ])
+
+    def __setitem__( self, k, v ):
+        if isinstance(v,_ParseResultsWithOffset):
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
+            sub = v[0]
+        elif isinstance(k,int):
+            self.__toklist[k] = v
+            sub = v
+        else:
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
+            sub = v
+        if isinstance(sub,ParseResults):
+            sub.__parent = wkref(self)
+
+    def __delitem__( self, i ):
+        if isinstance(i,(int,slice)):
+            mylen = len( self.__toklist )
+            del self.__toklist[i]
+
+            # convert int to slice
+            if isinstance(i, int):
+                if i < 0:
+                    i += mylen
+                i = slice(i, i+1)
+            # get removed indices
+            removed = list(range(*i.indices(mylen)))
+            removed.reverse()
+            # fixup indices in token dictionary
+            for name in self.__tokdict:
+                occurrences = self.__tokdict[name]
+                for j in removed:
+                    for k, (value, position) in enumerate(occurrences):
+                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
+        else:
+            del self.__tokdict[i]
+
+    def __contains__( self, k ):
+        return k in self.__tokdict
+
+    def __len__( self ): return len( self.__toklist )
+    def __bool__(self): return len( self.__toklist ) > 0
+    __nonzero__ = __bool__
+    def __iter__( self ): return iter( self.__toklist )
+    def __reversed__( self ): return iter( reversed(self.__toklist) )
+    def keys( self ):
+        """Returns all named result keys."""
+        return self.__tokdict.keys()
+
+    def pop( self, index=-1 ):
+        """Removes and returns item at specified index (default=last).
+           Will work with either numeric indices or dict-key indicies."""
+        ret = self[index]
+        del self[index]
+        return ret
+
+    def get(self, key, defaultValue=None):
+        """Returns named result matching the given key, or if there is no
+           such name, then returns the given defaultValue or None if no
+           defaultValue is specified."""
+        if key in self:
+            return self[key]
+        else:
+            return defaultValue
+
+    def insert( self, index, insStr ):
+        self.__toklist.insert(index, insStr)
+        # fixup indices in token dictionary
+        for name in self.__tokdict:
+            occurrences = self.__tokdict[name]
+            for k, (value, position) in enumerate(occurrences):
+                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
+
+    def items( self ):
+        """Returns all named result keys and values as a list of tuples."""
+        return [(k,self[k]) for k in self.__tokdict]
+
+    def values( self ):
+        """Returns all named result values."""
+        return [ v[-1][0] for v in self.__tokdict.values() ]
+
+    def __getattr__( self, name ):
+        if name not in self.__slots__:
+            if name in self.__tokdict:
+                if name not in self.__accumNames:
+                    return self.__tokdict[name][-1][0]
+                else:
+                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
+            else:
+                return ""
+        return None
+
+    def __add__( self, other ):
+        ret = self.copy()
+        ret += other
+        return ret
+
+    def __iadd__( self, other ):
+        if other.__tokdict:
+            offset = len(self.__toklist)
+            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
+            otheritems = other.__tokdict.items()
+            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
+                                for (k,vlist) in otheritems for v in vlist]
+            for k,v in otherdictitems:
+                self[k] = v
+                if isinstance(v[0],ParseResults):
+                    v[0].__parent = wkref(self)
+            
+        self.__toklist += other.__toklist
+        self.__accumNames.update( other.__accumNames )
+        del other
+        return self
+
+    def __repr__( self ):
+        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
+
+    def __str__( self ):
+        out = "["
+        sep = ""
+        for i in self.__toklist:
+            if isinstance(i, ParseResults):
+                out += sep + _ustr(i)
+            else:
+                out += sep + repr(i)
+            sep = ", "
+        out += "]"
+        return out
+
+    def _asStringList( self, sep='' ):
+        out = []
+        for item in self.__toklist:
+            if out and sep:
+                out.append(sep)
+            if isinstance( item, ParseResults ):
+                out += item._asStringList()
+            else:
+                out.append( _ustr(item) )
+        return out
+
+    def asList( self ):
+        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
+        out = []
+        for res in self.__toklist:
+            if isinstance(res,ParseResults):
+                out.append( res.asList() )
+            else:
+                out.append( res )
+        return out
+
+    def asDict( self ):
+        """Returns the named parse results as dictionary."""
+        return dict( self.items() )
+
+    def copy( self ):
+        """Returns a new copy of a ParseResults object."""
+        ret = ParseResults( self.__toklist )
+        ret.__tokdict = self.__tokdict.copy()
+        ret.__parent = self.__parent
+        ret.__accumNames.update( self.__accumNames )
+        ret.__name = self.__name
+        return ret
+
+    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
+        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
+        nl = "\n"
+        out = []
+        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
+                                                            for v in vlist ] )
+        nextLevelIndent = indent + "  "
+
+        # collapse out indents if formatting is not desired
+        if not formatted:
+            indent = ""
+            nextLevelIndent = ""
+            nl = ""
+
+        selfTag = None
+        if doctag is not None:
+            selfTag = doctag
+        else:
+            if self.__name:
+                selfTag = self.__name
+
+        if not selfTag:
+            if namedItemsOnly:
+                return ""
+            else:
+                selfTag = "ITEM"
+
+        out += [ nl, indent, "<", selfTag, ">" ]
+
+        worklist = self.__toklist
+        for i,res in enumerate(worklist):
+            if isinstance(res,ParseResults):
+                if i in namedItems:
+                    out += [ res.asXML(namedItems[i],
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+                else:
+                    out += [ res.asXML(None,
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+            else:
+                # individual token, see if there is a name for it
+                resTag = None
+                if i in namedItems:
+                    resTag = namedItems[i]
+                if not resTag:
+                    if namedItemsOnly:
+                        continue
+                    else:
+                        resTag = "ITEM"
+                xmlBodyText = _xml_escape(_ustr(res))
+                out += [ nl, nextLevelIndent, "<", resTag, ">",
+                                                xmlBodyText,
+                                                "</", resTag, ">" ]
+
+        out += [ nl, indent, "</", selfTag, ">" ]
+        return "".join(out)
+
+    def __lookup(self,sub):
+        for k,vlist in self.__tokdict.items():
+            for v,loc in vlist:
+                if sub is v:
+                    return k
+        return None
+
+    def getName(self):
+        """Returns the results name for this token expression."""
+        if self.__name:
+            return self.__name
+        elif self.__parent:
+            par = self.__parent()
+            if par:
+                return par.__lookup(self)
+            else:
+                return None
+        elif (len(self) == 1 and
+               len(self.__tokdict) == 1 and
+               self.__tokdict.values()[0][0][1] in (0,-1)):
+            return self.__tokdict.keys()[0]
+        else:
+            return None
+
+    def dump(self,indent='',depth=0):
+        """Diagnostic method for listing out the contents of a ParseResults.
+           Accepts an optional indent argument so that this string can be embedded
+           in a nested display of other data."""
+        out = []
+        out.append( indent+_ustr(self.asList()) )
+        keys = self.items()
+        keys.sort()
+        for k,v in keys:
+            if out:
+                out.append('\n')
+            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
+            if isinstance(v,ParseResults):
+                if v.keys():
+                    out.append( v.dump(indent,depth+1) )
+                else:
+                    out.append(_ustr(v))
+            else:
+                out.append(_ustr(v))
+        return "".join(out)
+
+    # add support for pickle protocol
+    def __getstate__(self):
+        return ( self.__toklist,
+                 ( self.__tokdict.copy(),
+                   self.__parent is not None and self.__parent() or None,
+                   self.__accumNames,
+                   self.__name ) )
+
+    def __setstate__(self,state):
+        self.__toklist = state[0]
+        self.__tokdict, \
+        par, \
+        inAccumNames, \
+        self.__name = state[1]
+        self.__accumNames = {}
+        self.__accumNames.update(inAccumNames)
+        if par is not None:
+            self.__parent = wkref(par)
+        else:
+            self.__parent = None
+
+    def __dir__(self):
+        return dir(super(ParseResults,self)) + self.keys()
+
+def col (loc,strg):
+    """Returns current column within a string, counting newlines as line separators.
+   The first column is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
+   on parsing strings containing <TAB>s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
+
+def lineno(loc,strg):
+    """Returns current line number within a string, counting newlines as line separators.
+   The first line is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
+   on parsing strings containing <TAB>s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return strg.count("\n",0,loc) + 1
+
+def line( loc, strg ):
+    """Returns the line of text containing loc within a string, counting newlines as line separators.
+       """
+    lastCR = strg.rfind("\n", 0, loc)
+    nextCR = strg.find("\n", loc)
+    if nextCR > 0:
+        return strg[lastCR+1:nextCR]
+    else:
+        return strg[lastCR+1:]
+
+def _defaultStartDebugAction( instring, loc, expr ):
+    print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+
+def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
+    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
+
+def _defaultExceptionDebugAction( instring, loc, expr, exc ):
+    print ("Exception raised:" + _ustr(exc))
+
+def nullDebugAction(*args):
+    """'Do-nothing' debug action, to suppress debugging output during parsing."""
+    pass
+
+class ParserElement(object):
+    """Abstract base level parser element class."""
+    DEFAULT_WHITE_CHARS = " \n\t\r"
+
+    def setDefaultWhitespaceChars( chars ):
+        """Overrides the default whitespace chars
+        """
+        ParserElement.DEFAULT_WHITE_CHARS = chars
+    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
+
+    def __init__( self, savelist=False ):
+        self.parseAction = list()
+        self.failAction = None
+        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
+        self.strRepr = None
+        self.resultsName = None
+        self.saveAsList = savelist
+        self.skipWhitespace = True
+        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        self.copyDefaultWhiteChars = True
+        self.mayReturnEmpty = False # used when checking for left-recursion
+        self.keepTabs = False
+        self.ignoreExprs = list()
+        self.debug = False
+        self.streamlined = False
+        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
+        self.errmsg = ""
+        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
+        self.debugActions = ( None, None, None ) #custom debug actions
+        self.re = None
+        self.callPreparse = True # used to avoid redundant calls to preParse
+        self.callDuringTry = False
+
+    def copy( self ):
+        """Make a copy of this ParserElement.  Useful for defining different parse actions
+           for the same parsing pattern, using copies of the original parse element."""
+        cpy = copy.copy( self )
+        cpy.parseAction = self.parseAction[:]
+        cpy.ignoreExprs = self.ignoreExprs[:]
+        if self.copyDefaultWhiteChars:
+            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        return cpy
+
+    def setName( self, name ):
+        """Define name for this expression, for use in debugging."""
+        self.name = name
+        self.errmsg = "Expected " + self.name
+        if hasattr(self,"exception"):
+            self.exception.msg = self.errmsg
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        """Define name for referencing matching tokens as a nested attribute
+           of the returned parse results.
+           NOTE: this returns a *copy* of the original ParserElement object;
+           this is so that the client can define a basic element, such as an
+           integer, and reference it in multiple places with different names.
+        """
+        newself = self.copy()
+        newself.resultsName = name
+        newself.modalResults = not listAllMatches
+        return newself
+
+    def setBreak(self,breakFlag = True):
+        """Method to invoke the Python pdb debugger when this element is
+           about to be parsed. Set breakFlag to True to enable, False to
+           disable.
+        """
+        if breakFlag:
+            _parseMethod = self._parse
+            def breaker(instring, loc, doActions=True, callPreParse=True):
+                import pdb
+                pdb.set_trace()
+                return _parseMethod( instring, loc, doActions, callPreParse )
+            breaker._originalParseMethod = _parseMethod
+            self._parse = breaker
+        else:
+            if hasattr(self._parse,"_originalParseMethod"):
+                self._parse = self._parse._originalParseMethod
+        return self
+
+    def _normalizeParseActionArgs( f ):
+        """Internal method used to decorate parse actions that take fewer than 3 arguments,
+           so that all parse actions can be called as f(s,l,t)."""
+        STAR_ARGS = 4
+
+        try:
+            restore = None
+            if isinstance(f,type):
+                restore = f
+                f = f.__init__
+            if not _PY3K:
+                codeObj = f.func_code
+            else:
+                codeObj = f.code
+            if codeObj.co_flags & STAR_ARGS:
+                return f
+            numargs = codeObj.co_argcount
+            if not _PY3K:
+                if hasattr(f,"im_self"):
+                    numargs -= 1
+            else:
+                if hasattr(f,"__self__"):
+                    numargs -= 1
+            if restore:
+                f = restore
+        except AttributeError:
+            try:
+                if not _PY3K:
+                    call_im_func_code = f.__call__.im_func.func_code
+                else:
+                    call_im_func_code = f.__code__
+
+                # not a function, must be a callable object, get info from the
+                # im_func binding of its bound __call__ method
+                if call_im_func_code.co_flags & STAR_ARGS:
+                    return f
+                numargs = call_im_func_code.co_argcount
+                if not _PY3K:
+                    if hasattr(f.__call__,"im_self"):
+                        numargs -= 1
+                else:
+                    if hasattr(f.__call__,"__self__"):
+                        numargs -= 0
+            except AttributeError:
+                if not _PY3K:
+                    call_func_code = f.__call__.func_code
+                else:
+                    call_func_code = f.__call__.__code__
+                # not a bound method, get info directly from __call__ method
+                if call_func_code.co_flags & STAR_ARGS:
+                    return f
+                numargs = call_func_code.co_argcount
+                if not _PY3K:
+                    if hasattr(f.__call__,"im_self"):
+                        numargs -= 1
+                else:
+                    if hasattr(f.__call__,"__self__"):
+                        numargs -= 1
+
+
+        #~ print ("adding function %s with %d args" % (f.func_name,numargs))
+        if numargs == 3:
+            return f
+        else:
+            if numargs > 3:
+                def tmp(s,l,t):
+                    return f(f.__call__.__self__, s,l,t)
+            if numargs == 2:
+                def tmp(s,l,t):
+                    return f(l,t)
+            elif numargs == 1:
+                def tmp(s,l,t):
+                    return f(t)
+            else: #~ numargs == 0:
+                def tmp(s,l,t):
+                    return f()
+            try:
+                tmp.__name__ = f.__name__
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            try:
+                tmp.__doc__ = f.__doc__
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            try:
+                tmp.__dict__.update(f.__dict__)
+            except (AttributeError,TypeError):
+                # no need for special handling if attribute doesnt exist
+                pass
+            return tmp
+    _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs)
+
+    def setParseAction( self, *fns, **kwargs ):
+        """Define action to perform when successfully matching parse element definition.
+           Parse action fn is a callable method with 0-3 arguments, called as fn(s,loc,toks),
+           fn(loc,toks), fn(toks), or just fn(), where:
+            - s   = the original string being parsed (see note below)
+            - loc = the location of the matching substring
+            - toks = a list of the matched tokens, packaged as a ParseResults object
+           If the functions in fns modify the tokens, they can return them as the return
+           value from fn, and the modified list of tokens will replace the original.
+           Otherwise, fn does not need to return any value.
+
+           Note: the default parsing behavior is to expand tabs in the input string
+           before starting the parsing process.  See L{I{parseString}<parseString>} for more information
+           on parsing strings containing <TAB>s, and suggested methods to maintain a
+           consistent view of the parsed string, the parse location, and line and column
+           positions within the parsed string.
+           """
+        self.parseAction = list(map(self._normalizeParseActionArgs, list(fns)))
+        self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
+        return self
+
+    def addParseAction( self, *fns, **kwargs ):
+        """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
+        self.parseAction += list(map(self._normalizeParseActionArgs, list(fns)))
+        self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
+        return self
+
+    def setFailAction( self, fn ):
+        """Define action to perform if parsing fails at this expression.
+           Fail acton fn is a callable function that takes the arguments
+           fn(s,loc,expr,err) where:
+            - s = string being parsed
+            - loc = location where expression match was attempted and failed
+            - expr = the parse expression that failed
+            - err = the exception thrown
+           The function returns no value.  It may throw ParseFatalException
+           if it is desired to stop parsing immediately."""
+        self.failAction = fn
+        return self
+
+    def _skipIgnorables( self, instring, loc ):
+        exprsFound = True
+        while exprsFound:
+            exprsFound = False
+            for e in self.ignoreExprs:
+                try:
+                    while 1:
+                        loc,dummy = e._parse( instring, loc )
+                        exprsFound = True
+                except ParseException:
+                    pass
+        return loc
+
+    def preParse( self, instring, loc ):
+        if self.ignoreExprs:
+            loc = self._skipIgnorables( instring, loc )
+
+        if self.skipWhitespace:
+            wt = self.whiteChars
+            instrlen = len(instring)
+            while loc < instrlen and instring[loc] in wt:
+                loc += 1
+
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        return loc, []
+
+    def postParse( self, instring, loc, tokenlist ):
+        return tokenlist
+
+    #~ @profile
+    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
+        debugging = ( self.debug ) #and doActions )
+
+        if debugging or self.failAction:
+            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+            if (self.debugActions[0] ):
+                self.debugActions[0]( instring, loc, self )
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = loc
+            try:
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            except ParseBaseException:
+                #~ print ("Exception raised:", err)
+                err = None
+                if self.debugActions[2]:
+                    err = sys.exc_info()[1]
+                    self.debugActions[2]( instring, tokensStart, self, err )
+                if self.failAction:
+                    if err is None:
+                        err = sys.exc_info()[1]
+                    self.failAction( instring, tokensStart, self, err )
+                raise
+        else:
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = loc
+            if self.mayIndexError or loc >= len(instring):
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            else:
+                loc,tokens = self.parseImpl( instring, preloc, doActions )
+
+        tokens = self.postParse( instring, loc, tokens )
+
+        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
+        if self.parseAction and (doActions or self.callDuringTry):
+            if debugging:
+                try:
+                    for fn in self.parseAction:
+                        tokens = fn( instring, tokensStart, retTokens )
+                        if tokens is not None:
+                            retTokens = ParseResults( tokens,
+                                                      self.resultsName,
+                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                      modal=self.modalResults )
+                except ParseBaseException:
+                    #~ print "Exception raised in user parse action:", err
+                    if (self.debugActions[2] ):
+                        err = sys.exc_info()[1]
+                        self.debugActions[2]( instring, tokensStart, self, err )
+                    raise
+            else:
+                for fn in self.parseAction:
+                    tokens = fn( instring, tokensStart, retTokens )
+                    if tokens is not None:
+                        retTokens = ParseResults( tokens,
+                                                  self.resultsName,
+                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                  modal=self.modalResults )
+
+        if debugging:
+            #~ print ("Matched",self,"->",retTokens.asList())
+            if (self.debugActions[1] ):
+                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
+
+        return loc, retTokens
+
+    def tryParse( self, instring, loc ):
+        try:
+            return self._parse( instring, loc, doActions=False )[0]
+        except ParseFatalException:
+            raise ParseException( instring, loc, self.errmsg, self)
+
+    # this method gets repeatedly called during backtracking with the same arguments -
+    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
+    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
+        lookup = (self,instring,loc,callPreParse,doActions)
+        if lookup in ParserElement._exprArgCache:
+            value = ParserElement._exprArgCache[ lookup ]
+            if isinstance(value,Exception):
+                raise value
+            return value
+        else:
+            try:
+                value = self._parseNoCache( instring, loc, doActions, callPreParse )
+                ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
+                return value
+            except ParseBaseException:
+                pe = sys.exc_info()[1]
+                ParserElement._exprArgCache[ lookup ] = pe
+                raise
+
+    _parse = _parseNoCache
+
+    # argument cache for optimizing repeated calls when backtracking through recursive expressions
+    _exprArgCache = {}
+    def resetCache():
+        ParserElement._exprArgCache.clear()
+    resetCache = staticmethod(resetCache)
+
+    _packratEnabled = False
+    def enablePackrat():
+        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
+           Repeated parse attempts at the same string location (which happens
+           often in many complex grammars) can immediately return a cached value,
+           instead of re-executing parsing/validating code.  Memoizing is done of
+           both valid results and parsing exceptions.
+
+           This speedup may break existing programs that use parse actions that
+           have side-effects.  For this reason, packrat parsing is disabled when
+           you first import pyparsing_py3 as pyparsing.  To activate the packrat feature, your
+           program must call the class method ParserElement.enablePackrat().  If
+           your program uses psyco to "compile as you go", you must call
+           enablePackrat before calling psyco.full().  If you do not do this,
+           Python will crash.  For best results, call enablePackrat() immediately
+           after importing pyparsing.
+        """
+        if not ParserElement._packratEnabled:
+            ParserElement._packratEnabled = True
+            ParserElement._parse = ParserElement._parseCache
+    enablePackrat = staticmethod(enablePackrat)
+
+    def parseString( self, instring, parseAll=False ):
+        """Execute the parse expression with the given string.
+           This is the main interface to the client code, once the complete
+           expression has been built.
+
+           If you want the grammar to require that the entire input string be
+           successfully parsed, then set parseAll to True (equivalent to ending
+           the grammar with StringEnd()).
+
+           Note: parseString implicitly calls expandtabs() on the input string,
+           in order to report proper column numbers in parse actions.
+           If the input string contains tabs and
+           the grammar uses parse actions that use the loc argument to index into the
+           string being parsed, you can ensure you have a consistent view of the input
+           string by:
+            - calling parseWithTabs on your grammar before calling parseString
+              (see L{I{parseWithTabs}<parseWithTabs>})
+            - define your parse action using the full (s,loc,toks) signature, and
+              reference the input string using the parse action's s argument
+            - explictly expand the tabs in your input string before calling
+              parseString
+        """
+        ParserElement.resetCache()
+        if not self.streamlined:
+            self.streamline()
+            #~ self.saveAsList = True
+        for e in self.ignoreExprs:
+            e.streamline()
+        if not self.keepTabs:
+            instring = instring.expandtabs()
+        try:
+            loc, tokens = self._parse( instring, 0 )
+            if parseAll:
+                loc = self.preParse( instring, loc )
+                StringEnd()._parse( instring, loc )
+        except ParseBaseException:
+            exc = sys.exc_info()[1]
+            # catch and re-raise exception from here, clears out pyparsing internal stack trace
+            raise exc
+        else:
+            return tokens
+
+    def scanString( self, instring, maxMatches=_MAX_INT ):
+        """Scan the input string for expression matches.  Each match will return the
+           matching tokens, start location, and end location.  May be called with optional
+           maxMatches argument, to clip scanning after 'n' matches are found.
+
+           Note that the start and end locations are reported relative to the string
+           being parsed.  See L{I{parseString}<parseString>} for more information on parsing
+           strings with embedded tabs."""
+        if not self.streamlined:
+            self.streamline()
+        for e in self.ignoreExprs:
+            e.streamline()
+
+        if not self.keepTabs:
+            instring = _ustr(instring).expandtabs()
+        instrlen = len(instring)
+        loc = 0
+        preparseFn = self.preParse
+        parseFn = self._parse
+        ParserElement.resetCache()
+        matches = 0
+        try:
+            while loc <= instrlen and matches < maxMatches:
+                try:
+                    preloc = preparseFn( instring, loc )
+                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
+                except ParseException:
+                    loc = preloc+1
+                else:
+                    if nextLoc > loc:
+                        matches += 1
+                        yield tokens, preloc, nextLoc
+                        loc = nextLoc
+                    else:
+                        loc = preloc+1
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def transformString( self, instring ):
+        """Extension to scanString, to modify matching text with modified tokens that may
+           be returned from a parse action.  To use transformString, define a grammar and
+           attach a parse action to it that modifies the returned token list.
+           Invoking transformString() on a target string will then scan for matches,
+           and replace the matched text patterns according to the logic in the parse
+           action.  transformString() returns the resulting transformed string."""
+        out = []
+        lastE = 0
+        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
+        # keep string locs straight between transformString and scanString
+        self.keepTabs = True
+        try:
+            for t,s,e in self.scanString( instring ):
+                out.append( instring[lastE:s] )
+                if t:
+                    if isinstance(t,ParseResults):
+                        out += t.asList()
+                    elif isinstance(t,list):
+                        out += t
+                    else:
+                        out.append(t)
+                lastE = e
+            out.append(instring[lastE:])
+            return "".join(map(_ustr,out))
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def searchString( self, instring, maxMatches=_MAX_INT ):
+        """Another extension to scanString, simplifying the access to the tokens found
+           to match the given parse expression.  May be called with optional
+           maxMatches argument, to clip searching after 'n' matches are found.
+        """
+        try:
+            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
+        except ParseBaseException:
+            pe = sys.exc_info()[1]
+            raise pe
+
+    def __add__(self, other ):
+        """Implementation of + operator - returns And"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, other ] )
+
+    def __radd__(self, other ):
+        """Implementation of + operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other + self
+
+    def __sub__(self, other):
+        """Implementation of - operator, returns And with error stop"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, And._ErrorStop(), other ] )
+
+    def __rsub__(self, other ):
+        """Implementation of - operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other - self
+
+    def __mul__(self,other):
+        if isinstance(other,int):
+            minElements, optElements = other,0
+        elif isinstance(other,tuple):
+            other = (other + (None, None))[:2]
+            if other[0] is None:
+                other = (0, other[1])
+            if isinstance(other[0],int) and other[1] is None:
+                if other[0] == 0:
+                    return ZeroOrMore(self)
+                if other[0] == 1:
+                    return OneOrMore(self)
+                else:
+                    return self*other[0] + ZeroOrMore(self)
+            elif isinstance(other[0],int) and isinstance(other[1],int):
+                minElements, optElements = other
+                optElements -= minElements
+            else:
+                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
+        else:
+            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
+
+        if minElements < 0:
+            raise ValueError("cannot multiply ParserElement by negative value")
+        if optElements < 0:
+            raise ValueError("second tuple value must be greater or equal to first tuple value")
+        if minElements == optElements == 0:
+            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
+
+        if (optElements):
+            def makeOptionalList(n):
+                if n>1:
+                    return Optional(self + makeOptionalList(n-1))
+                else:
+                    return Optional(self)
+            if minElements:
+                if minElements == 1:
+                    ret = self + makeOptionalList(optElements)
+                else:
+                    ret = And([self]*minElements) + makeOptionalList(optElements)
+            else:
+                ret = makeOptionalList(optElements)
+        else:
+            if minElements == 1:
+                ret = self
+            else:
+                ret = And([self]*minElements)
+        return ret
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __or__(self, other ):
+        """Implementation of | operator - returns MatchFirst"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return MatchFirst( [ self, other ] )
+
+    def __ror__(self, other ):
+        """Implementation of | operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other | self
+
+    def __xor__(self, other ):
+        """Implementation of ^ operator - returns Or"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Or( [ self, other ] )
+
+    def __rxor__(self, other ):
+        """Implementation of ^ operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other ^ self
+
+    def __and__(self, other ):
+        """Implementation of & operator - returns Each"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Each( [ self, other ] )
+
+    def __rand__(self, other ):
+        """Implementation of & operator when left operand is not a ParserElement"""
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other & self
+
+    def __invert__( self ):
+        """Implementation of ~ operator - returns NotAny"""
+        return NotAny( self )
+
+    def __call__(self, name):
+        """Shortcut for setResultsName, with listAllMatches=default::
+             userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
+           could be written as::
+             userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
+           """
+        return self.setResultsName(name)
+
+    def suppress( self ):
+        """Suppresses the output of this ParserElement; useful to keep punctuation from
+           cluttering up returned output.
+        """
+        return Suppress( self )
+
+    def leaveWhitespace( self ):
+        """Disables the skipping of whitespace before matching the characters in the
+           ParserElement's defined pattern.  This is normally only used internally by
+           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
+        """
+        self.skipWhitespace = False
+        return self
+
+    def setWhitespaceChars( self, chars ):
+        """Overrides the default whitespace chars
+        """
+        self.skipWhitespace = True
+        self.whiteChars = chars
+        self.copyDefaultWhiteChars = False
+        return self
+
+    def parseWithTabs( self ):
+        """Overrides default behavior to expand <TAB>s to spaces before parsing the input string.
+           Must be called before parseString when the input grammar contains elements that
+           match <TAB> characters."""
+        self.keepTabs = True
+        return self
+
+    def ignore( self, other ):
+        """Define expression to be ignored (e.g., comments) while doing pattern
+           matching; may be called repeatedly, to define multiple comment or other
+           ignorable patterns.
+        """
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                self.ignoreExprs.append( other )
+        else:
+            self.ignoreExprs.append( Suppress( other ) )
+        return self
+
+    def setDebugActions( self, startAction, successAction, exceptionAction ):
+        """Enable display of debugging messages while doing pattern matching."""
+        self.debugActions = (startAction or _defaultStartDebugAction,
+                             successAction or _defaultSuccessDebugAction,
+                             exceptionAction or _defaultExceptionDebugAction)
+        self.debug = True
+        return self
+
+    def setDebug( self, flag=True ):
+        """Enable display of debugging messages while doing pattern matching.
+           Set flag to True to enable, False to disable."""
+        if flag:
+            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
+        else:
+            self.debug = False
+        return self
+
+    def __str__( self ):
+        return self.name
+
+    def __repr__( self ):
+        return _ustr(self)
+
+    def streamline( self ):
+        self.streamlined = True
+        self.strRepr = None
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        pass
+
+    def validate( self, validateTrace=[] ):
+        """Check defined expressions for valid structure, check for infinite recursive definitions."""
+        self.checkRecursion( [] )
+
+    def parseFile( self, file_or_filename, parseAll=False ):
+        """Execute the parse expression on the given file or filename.
+           If a filename is specified (instead of a file object),
+           the entire file is opened, read, and closed before parsing.
+        """
+        try:
+            file_contents = file_or_filename.read()
+        except AttributeError:
+            f = open(file_or_filename, "rb")
+            file_contents = f.read()
+            f.close()
+        try:
+            return self.parseString(file_contents, parseAll)
+        except ParseBaseException:
+            # catch and re-raise exception from here, clears out pyparsing internal stack trace
+            exc = sys.exc_info()[1]
+            raise exc
+
+    def getException(self):
+        return ParseException("",0,self.errmsg,self)
+
+    def __getattr__(self,aname):
+        if aname == "myException":
+            self.myException = ret = self.getException();
+            return ret;
+        else:
+            raise AttributeError("no such attribute " + aname)
+
+    def __eq__(self,other):
+        if isinstance(other, ParserElement):
+            return self is other or self.__dict__ == other.__dict__
+        elif isinstance(other, basestring):
+            try:
+                self.parseString(_ustr(other), parseAll=True)
+                return True
+            except ParseBaseException:
+                return False
+        else:
+            return super(ParserElement,self)==other
+
+    def __ne__(self,other):
+        return not (self == other)
+
+    def __hash__(self):
+        return hash(id(self))
+
+    def __req__(self,other):
+        return self == other
+
+    def __rne__(self,other):
+        return not (self == other)
+
+
+class Token(ParserElement):
+    """Abstract ParserElement subclass, for defining atomic matching patterns."""
+    def __init__( self ):
+        super(Token,self).__init__( savelist=False )
+        #self.myException = ParseException("",0,"",self)
+
+    def setName(self, name):
+        s = super(Token,self).setName(name)
+        self.errmsg = "Expected " + self.name
+        #s.myException.msg = self.errmsg
+        return s
+
+
+class Empty(Token):
+    """An empty token, will always match."""
+    def __init__( self ):
+        super(Empty,self).__init__()
+        self.name = "Empty"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+
+class NoMatch(Token):
+    """A token that will never match."""
+    def __init__( self ):
+        super(NoMatch,self).__init__()
+        self.name = "NoMatch"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.errmsg = "Unmatchable token"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+
+class Literal(Token):
+    """Token to exactly match a specified string."""
+    def __init__( self, matchString ):
+        super(Literal,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Literal; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+            self.__class__ = Empty
+        self.name = '"%s"' % _ustr(self.match)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+
+    # Performance tuning: this routine gets called a *lot*
+    # if this is a single character match string  and the first character matches,
+    # short-circuit as quickly as possible, and avoid calling startswith
+    #~ @profile
+    def parseImpl( self, instring, loc, doActions=True ):
+        if (instring[loc] == self.firstMatchChar and
+            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
+            return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+_L = Literal
+
+class Keyword(Token):
+    """Token to exactly match a specified string as a keyword, that is, it must be
+       immediately followed by a non-keyword character.  Compare with Literal::
+         Literal("if") will match the leading 'if' in 'ifAndOnlyIf'.
+         Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)'
+       Accepts two optional constructor arguments in addition to the keyword string:
+       identChars is a string of characters that would be valid identifier characters,
+       defaulting to all alphanumerics + "_" and "$"; caseless allows case-insensitive
+       matching, default is False.
+    """
+    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
+
+    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
+        super(Keyword,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Keyword; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+        self.name = '"%s"' % self.match
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.caseless = caseless
+        if caseless:
+            self.caselessmatch = matchString.upper()
+            identChars = identChars.upper()
+        self.identChars = _str2dict(identChars)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.caseless:
+            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
+                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        else:
+            if (instring[loc] == self.firstMatchChar and
+                (self.matchLen==1 or instring.startswith(self.match,loc)) and
+                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
+                (loc == 0 or instring[loc-1] not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+    def copy(self):
+        c = super(Keyword,self).copy()
+        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        return c
+
+    def setDefaultKeywordChars( chars ):
+        """Overrides the default Keyword chars
+        """
+        Keyword.DEFAULT_KEYWORD_CHARS = chars
+    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
+
+class CaselessLiteral(Literal):
+    """Token to match a specified string, ignoring case of letters.
+       Note: the matched results will always be in the case of the given
+       match string, NOT the case of the input text.
+    """
+    def __init__( self, matchString ):
+        super(CaselessLiteral,self).__init__( matchString.upper() )
+        # Preserve the defining literal.
+        self.returnString = matchString
+        self.name = "'%s'" % self.returnString
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[ loc:loc+self.matchLen ].upper() == self.match:
+            return loc+self.matchLen, self.returnString
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class CaselessKeyword(Keyword):
+    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
+        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
+            return loc+self.matchLen, self.match
+        #~ raise ParseException( instring, loc, self.errmsg )
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class Word(Token):
+    """Token for matching words composed of allowed character sets.
+       Defined with string containing all allowed initial characters,
+       an optional string containing allowed body characters (if omitted,
+       defaults to the initial character set), and an optional minimum,
+       maximum, and/or exact length.  The default value for min is 1 (a
+       minimum value < 1 is not valid); the default values for max and exact
+       are 0, meaning no maximum or exact length restriction.
+    """
+    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ):
+        super(Word,self).__init__()
+        self.initCharsOrig = initChars
+        self.initChars = _str2dict(initChars)
+        if bodyChars :
+            self.bodyCharsOrig = bodyChars
+            self.bodyChars = _str2dict(bodyChars)
+        else:
+            self.bodyCharsOrig = initChars
+            self.bodyChars = _str2dict(initChars)
+
+        self.maxSpecified = max > 0
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.asKeyword = asKeyword
+
+        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
+            if self.bodyCharsOrig == self.initCharsOrig:
+                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
+            elif len(self.bodyCharsOrig) == 1:
+                self.reString = "%s[%s]*" % \
+                                      (re.escape(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            else:
+                self.reString = "[%s][%s]*" % \
+                                      (_escapeRegexRangeChars(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            if self.asKeyword:
+                self.reString = r"\b"+self.reString+r"\b"
+            try:
+                self.re = re.compile( self.reString )
+            except:
+                self.re = None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.re:
+            result = self.re.match(instring,loc)
+            if not result:
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+
+            loc = result.end()
+            return loc,result.group()
+
+        if not(instring[ loc ] in self.initChars):
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        start = loc
+        loc += 1
+        instrlen = len(instring)
+        bodychars = self.bodyChars
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, instrlen )
+        while loc < maxloc and instring[loc] in bodychars:
+            loc += 1
+
+        throwException = False
+        if loc - start < self.minLen:
+            throwException = True
+        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
+            throwException = True
+        if self.asKeyword:
+            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
+                throwException = True
+
+        if throwException:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(Word,self).__str__()
+        except:
+            pass
+
+
+        if self.strRepr is None:
+
+            def charsAsStr(s):
+                if len(s)>4:
+                    return s[:4]+"..."
+                else:
+                    return s
+
+            if ( self.initCharsOrig != self.bodyCharsOrig ):
+                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
+            else:
+                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
+
+        return self.strRepr
+
+
+class Regex(Token):
+    """Token for matching strings that match a given regular expression.
+       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
+    """
+    def __init__( self, pattern, flags=0):
+        """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags."""
+        super(Regex,self).__init__()
+
+        if len(pattern) == 0:
+            warnings.warn("null string passed to Regex; use Empty() instead",
+                    SyntaxWarning, stacklevel=2)
+
+        self.pattern = pattern
+        self.flags = flags
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = self.re.match(instring,loc)
+        if not result:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        loc = result.end()
+        d = result.groupdict()
+        ret = ParseResults(result.group())
+        if d:
+            for k in d:
+                ret[k] = d[k]
+        return loc,ret
+
+    def __str__( self ):
+        try:
+            return super(Regex,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "Re:(%s)" % repr(self.pattern)
+
+        return self.strRepr
+
+
+class QuotedString(Token):
+    """Token for matching strings that are delimited by quoting characters.
+    """
+    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
+        """
+           Defined with the following parameters:
+            - quoteChar - string of one or more characters defining the quote delimiting string
+            - escChar - character to escape quotes, typically backslash (default=None)
+            - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
+            - multiline - boolean indicating whether quotes can span multiple lines (default=False)
+            - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
+            - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
+        """
+        super(QuotedString,self).__init__()
+
+        # remove white space from quote chars - wont work anyway
+        quoteChar = quoteChar.strip()
+        if len(quoteChar) == 0:
+            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+            raise SyntaxError()
+
+        if endQuoteChar is None:
+            endQuoteChar = quoteChar
+        else:
+            endQuoteChar = endQuoteChar.strip()
+            if len(endQuoteChar) == 0:
+                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+                raise SyntaxError()
+
+        self.quoteChar = quoteChar
+        self.quoteCharLen = len(quoteChar)
+        self.firstQuoteChar = quoteChar[0]
+        self.endQuoteChar = endQuoteChar
+        self.endQuoteCharLen = len(endQuoteChar)
+        self.escChar = escChar
+        self.escQuote = escQuote
+        self.unquoteResults = unquoteResults
+
+        if multiline:
+            self.flags = re.MULTILINE | re.DOTALL
+            self.pattern = r'%s(?:[^%s%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        else:
+            self.flags = 0
+            self.pattern = r'%s(?:[^%s\n\r%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        if len(self.endQuoteChar) > 1:
+            self.pattern += (
+                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
+                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
+                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
+                )
+        if escQuote:
+            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
+        if escChar:
+            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
+            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
+        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
+        if not result:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        loc = result.end()
+        ret = result.group()
+
+        if self.unquoteResults:
+
+            # strip off quotes
+            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
+
+            if isinstance(ret,basestring):
+                # replace escaped characters
+                if self.escChar:
+                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
+
+                # replace escaped quotes
+                if self.escQuote:
+                    ret = ret.replace(self.escQuote, self.endQuoteChar)
+
+        return loc, ret
+
+    def __str__( self ):
+        try:
+            return super(QuotedString,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
+
+        return self.strRepr
+
+
+class CharsNotIn(Token):
+    """Token for matching words composed of characters *not* in a given set.
+       Defined with string containing all disallowed characters, and an optional
+       minimum, maximum, and/or exact length.  The default value for min is 1 (a
+       minimum value < 1 is not valid); the default values for max and exact
+       are 0, meaning no maximum or exact length restriction.
+    """
+    def __init__( self, notChars, min=1, max=0, exact=0 ):
+        super(CharsNotIn,self).__init__()
+        self.skipWhitespace = False
+        self.notChars = notChars
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = ( self.minLen == 0 )
+        #self.myException.msg = self.errmsg
+        self.mayIndexError = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[loc] in self.notChars:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        start = loc
+        loc += 1
+        notchars = self.notChars
+        maxlen = min( start+self.maxLen, len(instring) )
+        while loc < maxlen and \
+              (instring[loc] not in notchars):
+            loc += 1
+
+        if loc - start < self.minLen:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(CharsNotIn, self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            if len(self.notChars) > 4:
+                self.strRepr = "!W:(%s...)" % self.notChars[:4]
+            else:
+                self.strRepr = "!W:(%s)" % self.notChars
+
+        return self.strRepr
+
+class White(Token):
+    """Special matching class for matching whitespace.  Normally, whitespace is ignored
+       by pyparsing grammars.  This class is included when some whitespace structures
+       are significant.  Define with a string containing the whitespace characters to be
+       matched; default is " \\t\\r\\n".  Also takes optional min, max, and exact arguments,
+       as defined for the Word class."""
+    whiteStrs = {
+        " " : "<SPC>",
+        "\t": "<TAB>",
+        "\n": "<LF>",
+        "\r": "<CR>",
+        "\f": "<FF>",
+        }
+    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
+        super(White,self).__init__()
+        self.matchWhite = ws
+        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
+        #~ self.leaveWhitespace()
+        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
+        self.mayReturnEmpty = True
+        self.errmsg = "Expected " + self.name
+        #self.myException.msg = self.errmsg
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not(instring[ loc ] in self.matchWhite):
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        start = loc
+        loc += 1
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, len(instring) )
+        while loc < maxloc and instring[loc] in self.matchWhite:
+            loc += 1
+
+        if loc - start < self.minLen:
+            #~ raise ParseException( instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+        return loc, instring[start:loc]
+
+
+class _PositionToken(Token):
+    def __init__( self ):
+        super(_PositionToken,self).__init__()
+        self.name=self.__class__.__name__
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+class GoToColumn(_PositionToken):
+    """Token to advance to a specific column of input text; useful for tabular report scraping."""
+    def __init__( self, colno ):
+        super(GoToColumn,self).__init__()
+        self.col = colno
+
+    def preParse( self, instring, loc ):
+        if col(loc,instring) != self.col:
+            instrlen = len(instring)
+            if self.ignoreExprs:
+                loc = self._skipIgnorables( instring, loc )
+            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
+                loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        thiscol = col( loc, instring )
+        if thiscol > self.col:
+            raise ParseException( instring, loc, "Text not in expected column", self )
+        newloc = loc + self.col - thiscol
+        ret = instring[ loc: newloc ]
+        return newloc, ret
+
+class LineStart(_PositionToken):
+    """Matches if current position is at the beginning of a line within the parse string"""
+    def __init__( self ):
+        super(LineStart,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected start of line"
+        #self.myException.msg = self.errmsg
+
+    def preParse( self, instring, loc ):
+        preloc = super(LineStart,self).preParse(instring,loc)
+        if instring[preloc] == "\n":
+            loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not( loc==0 or
+            (loc == self.preParse( instring, 0 )) or
+            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
+            #~ raise ParseException( instring, loc, "Expected start of line" )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        return loc, []
+
+class LineEnd(_PositionToken):
+    """Matches if current position is at the end of a line within the parse string"""
+    def __init__( self ):
+        super(LineEnd,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected end of line"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc<len(instring):
+            if instring[loc] == "\n":
+                return loc+1, "\n"
+            else:
+                #~ raise ParseException( instring, loc, "Expected end of line" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        elif loc == len(instring):
+            return loc+1, []
+        else:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+class StringStart(_PositionToken):
+    """Matches if current position is at the beginning of the parse string"""
+    def __init__( self ):
+        super(StringStart,self).__init__()
+        self.errmsg = "Expected start of text"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc != 0:
+            # see if entire string up to here is just whitespace and ignoreables
+            if loc != self.preParse( instring, 0 ):
+                #~ raise ParseException( instring, loc, "Expected start of text" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+class StringEnd(_PositionToken):
+    """Matches if current position is at the end of the parse string"""
+    def __init__( self ):
+        super(StringEnd,self).__init__()
+        self.errmsg = "Expected end of text"
+        #self.myException.msg = self.errmsg
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc < len(instring):
+            #~ raise ParseException( instring, loc, "Expected end of text" )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        elif loc == len(instring):
+            return loc+1, []
+        elif loc > len(instring):
+            return loc, []
+        else:
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+
+class WordStart(_PositionToken):
+    """Matches if the current position is at the beginning of a Word, and
+       is not preceded by any character in a given set of wordChars
+       (default=printables). To emulate the \b behavior of regular expressions,
+       use WordStart(alphanums). WordStart will also match at the beginning of
+       the string being parsed, or at the beginning of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordStart,self).__init__()
+        self.wordChars = _str2dict(wordChars)
+        self.errmsg = "Not at the start of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        if loc != 0:
+            if (instring[loc-1] in self.wordChars or
+                instring[loc] not in self.wordChars):
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+class WordEnd(_PositionToken):
+    """Matches if the current position is at the end of a Word, and
+       is not followed by any character in a given set of wordChars
+       (default=printables). To emulate the \b behavior of regular expressions,
+       use WordEnd(alphanums). WordEnd will also match at the end of
+       the string being parsed, or at the end of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordEnd,self).__init__()
+        self.wordChars = _str2dict(wordChars)
+        self.skipWhitespace = False
+        self.errmsg = "Not at the end of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        instrlen = len(instring)
+        if instrlen>0 and loc<instrlen:
+            if (instring[loc] in self.wordChars or
+                instring[loc-1] not in self.wordChars):
+                #~ raise ParseException( instring, loc, "Expected end of word" )
+                exc = self.myException
+                exc.loc = loc
+                exc.pstr = instring
+                raise exc
+        return loc, []
+
+
+class ParseExpression(ParserElement):
+    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
+    def __init__( self, exprs, savelist = False ):
+        super(ParseExpression,self).__init__(savelist)
+        if isinstance( exprs, list ):
+            self.exprs = exprs
+        elif isinstance( exprs, basestring ):
+            self.exprs = [ Literal( exprs ) ]
+        else:
+            try:
+                self.exprs = list( exprs )
+            except TypeError:
+                self.exprs = [ exprs ]
+        self.callPreparse = False
+
+    def __getitem__( self, i ):
+        return self.exprs[i]
+
+    def append( self, other ):
+        self.exprs.append( other )
+        self.strRepr = None
+        return self
+
+    def leaveWhitespace( self ):
+        """Extends leaveWhitespace defined in base class, and also invokes leaveWhitespace on
+           all contained expressions."""
+        self.skipWhitespace = False
+        self.exprs = [ e.copy() for e in self.exprs ]
+        for e in self.exprs:
+            e.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseExpression, self).ignore( other )
+                for e in self.exprs:
+                    e.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseExpression, self).ignore( other )
+            for e in self.exprs:
+                e.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def __str__( self ):
+        try:
+            return super(ParseExpression,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
+        return self.strRepr
+
+    def streamline( self ):
+        super(ParseExpression,self).streamline()
+
+        for e in self.exprs:
+            e.streamline()
+
+        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
+        # but only if there are no parse actions or resultsNames on the nested And's
+        # (likewise for Or's and MatchFirst's)
+        if ( len(self.exprs) == 2 ):
+            other = self.exprs[0]
+            if ( isinstance( other, self.__class__ ) and
+                  not(other.parseAction) and
+                  other.resultsName is None and
+                  not other.debug ):
+                self.exprs = other.exprs[:] + [ self.exprs[1] ]
+                self.strRepr = None
+                self.mayReturnEmpty |= other.mayReturnEmpty
+                self.mayIndexError  |= other.mayIndexError
+
+            other = self.exprs[-1]
+            if ( isinstance( other, self.__class__ ) and
+                  not(other.parseAction) and
+                  other.resultsName is None and
+                  not other.debug ):
+                self.exprs = self.exprs[:-1] + other.exprs[:]
+                self.strRepr = None
+                self.mayReturnEmpty |= other.mayReturnEmpty
+                self.mayIndexError  |= other.mayIndexError
+
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
+        return ret
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        for e in self.exprs:
+            e.validate(tmp)
+        self.checkRecursion( [] )
+
+class And(ParseExpression):
+    """Requires all given ParseExpressions to be found in the given order.
+       Expressions may be separated by whitespace.
+       May be constructed using the '+' operator.
+    """
+
+    class _ErrorStop(Empty):
+        def __init__(self, *args, **kwargs):
+            super(Empty,self).__init__(*args, **kwargs)
+            self.leaveWhitespace()
+
+    def __init__( self, exprs, savelist = True ):
+        super(And,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = True
+        for e in self.exprs:
+            if not e.mayReturnEmpty:
+                self.mayReturnEmpty = False
+                break
+        self.setWhitespaceChars( exprs[0].whiteChars )
+        self.skipWhitespace = exprs[0].skipWhitespace
+        self.callPreparse = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        # pass False as last arg to _parse for first element, since we already
+        # pre-parsed the string as part of our And pre-parsing
+        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
+        errorStop = False
+        for e in self.exprs[1:]:
+            if isinstance(e, And._ErrorStop):
+                errorStop = True
+                continue
+            if errorStop:
+                try:
+                    loc, exprtokens = e._parse( instring, loc, doActions )
+                except ParseSyntaxException:
+                    raise
+                except ParseBaseException:
+                    pe = sys.exc_info()[1]
+                    raise ParseSyntaxException(pe)
+                except IndexError:
+                    raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
+            else:
+                loc, exprtokens = e._parse( instring, loc, doActions )
+            if exprtokens or exprtokens.keys():
+                resultlist += exprtokens
+        return loc, resultlist
+
+    def __iadd__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #And( [ self, other ] )
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+            if not e.mayReturnEmpty:
+                break
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+
+class Or(ParseExpression):
+    """Requires that at least one ParseExpression is found.
+       If two expressions match, the expression that matches the longest string will be used.
+       May be constructed using the '^' operator.
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(Or,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = False
+        for e in self.exprs:
+            if e.mayReturnEmpty:
+                self.mayReturnEmpty = True
+                break
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxMatchLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                loc2 = e.tryParse( instring, loc )
+            except ParseException:
+                err = sys.exc_info()[1]
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+            else:
+                if loc2 > maxMatchLoc:
+                    maxMatchLoc = loc2
+                    maxMatchExp = e
+
+        if maxMatchLoc < 0:
+            if maxException is not None:
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+        return maxMatchExp._parse( instring, loc, doActions )
+
+    def __ixor__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #Or( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class MatchFirst(ParseExpression):
+    """Requires that at least one ParseExpression is found.
+       If two expressions match, the first one listed is the one that will match.
+       May be constructed using the '|' operator.
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(MatchFirst,self).__init__(exprs, savelist)
+        if exprs:
+            self.mayReturnEmpty = False
+            for e in self.exprs:
+                if e.mayReturnEmpty:
+                    self.mayReturnEmpty = True
+                    break
+        else:
+            self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                ret = e._parse( instring, loc, doActions )
+                return ret
+            except ParseException as err:
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+
+        # only got here if no expression matched, raise exception for match that made it the furthest
+        else:
+            if maxException is not None:
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+    def __ior__(self, other ):
+        if isinstance( other, basestring ):
+            other = Literal( other )
+        return self.append( other ) #MatchFirst( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class Each(ParseExpression):
+    """Requires all given ParseExpressions to be found, but in any order.
+       Expressions may be separated by whitespace.
+       May be constructed using the '&' operator.
+    """
+    def __init__( self, exprs, savelist = True ):
+        super(Each,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = True
+        for e in self.exprs:
+            if not e.mayReturnEmpty:
+                self.mayReturnEmpty = False
+                break
+        self.skipWhitespace = True
+        self.initExprGroups = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.initExprGroups:
+            self.optionals = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
+            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
+            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
+            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
+            self.required += self.multirequired
+            self.initExprGroups = False
+        tmpLoc = loc
+        tmpReqd = self.required[:]
+        tmpOpt  = self.optionals[:]
+        matchOrder = []
+
+        keepMatching = True
+        while keepMatching:
+            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
+            failed = []
+            for e in tmpExprs:
+                try:
+                    tmpLoc = e.tryParse( instring, tmpLoc )
+                except ParseException:
+                    failed.append(e)
+                else:
+                    matchOrder.append(e)
+                    if e in tmpReqd:
+                        tmpReqd.remove(e)
+                    elif e in tmpOpt:
+                        tmpOpt.remove(e)
+            if len(failed) == len(tmpExprs):
+                keepMatching = False
+
+        if tmpReqd:
+            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
+            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
+
+        # add any unmatched Optionals, in case they have default values defined
+        matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt)
+
+        resultlist = []
+        for e in matchOrder:
+            loc,results = e._parse(instring,loc,doActions)
+            resultlist.append(results)
+
+        finalResults = ParseResults([])
+        for r in resultlist:
+            dups = {}
+            for k in r.keys():
+                if k in finalResults.keys():
+                    tmp = ParseResults(finalResults[k])
+                    tmp += ParseResults(r[k])
+                    dups[k] = tmp
+            finalResults += ParseResults(r)
+            for k,v in dups.items():
+                finalResults[k] = v
+        return loc, finalResults
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class ParseElementEnhance(ParserElement):
+    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
+    def __init__( self, expr, savelist=False ):
+        super(ParseElementEnhance,self).__init__(savelist)
+        if isinstance( expr, basestring ):
+            expr = Literal(expr)
+        self.expr = expr
+        self.strRepr = None
+        if expr is not None:
+            self.mayIndexError = expr.mayIndexError
+            self.mayReturnEmpty = expr.mayReturnEmpty
+            self.setWhitespaceChars( expr.whiteChars )
+            self.skipWhitespace = expr.skipWhitespace
+            self.saveAsList = expr.saveAsList
+            self.callPreparse = expr.callPreparse
+            self.ignoreExprs.extend(expr.ignoreExprs)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr is not None:
+            return self.expr._parse( instring, loc, doActions, callPreParse=False )
+        else:
+            raise ParseException("",loc,self.errmsg,self)
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        self.expr = self.expr.copy()
+        if self.expr is not None:
+            self.expr.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseElementEnhance, self).ignore( other )
+                if self.expr is not None:
+                    self.expr.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseElementEnhance, self).ignore( other )
+            if self.expr is not None:
+                self.expr.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def streamline( self ):
+        super(ParseElementEnhance,self).streamline()
+        if self.expr is not None:
+            self.expr.streamline()
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        if self in parseElementList:
+            raise RecursiveGrammarException( parseElementList+[self] )
+        subRecCheckList = parseElementList[:] + [ self ]
+        if self.expr is not None:
+            self.expr.checkRecursion( subRecCheckList )
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        if self.expr is not None:
+            self.expr.validate(tmp)
+        self.checkRecursion( [] )
+
+    def __str__( self ):
+        try:
+            return super(ParseElementEnhance,self).__str__()
+        except:
+            pass
+
+        if self.strRepr is None and self.expr is not None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
+        return self.strRepr
+
+
+class FollowedBy(ParseElementEnhance):
+    """Lookahead matching of the given parse expression.  FollowedBy
+    does *not* advance the parsing position within the input string, it only
+    verifies that the specified parse expression matches at the current
+    position.  FollowedBy always returns a null token list."""
+    def __init__( self, expr ):
+        super(FollowedBy,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self.expr.tryParse( instring, loc )
+        return loc, []
+
+
+class NotAny(ParseElementEnhance):
+    """Lookahead to disallow matching with the given parse expression.  NotAny
+    does *not* advance the parsing position within the input string, it only
+    verifies that the specified parse expression does *not* match at the current
+    position.  Also, NotAny does *not* skip over leading whitespace. NotAny
+    always returns a null token list.  May be constructed using the '~' operator."""
+    def __init__( self, expr ):
+        super(NotAny,self).__init__(expr)
+        #~ self.leaveWhitespace()
+        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
+        self.mayReturnEmpty = True
+        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
+        #self.myException = ParseException("",0,self.errmsg,self)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            self.expr.tryParse( instring, loc )
+        except (ParseException,IndexError):
+            pass
+        else:
+            #~ raise ParseException(instring, loc, self.errmsg )
+            exc = self.myException
+            exc.loc = loc
+            exc.pstr = instring
+            raise exc
+        return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "~{" + _ustr(self.expr) + "}"
+
+        return self.strRepr
+
+
+class ZeroOrMore(ParseElementEnhance):
+    """Optional repetition of zero or more of the given expression."""
+    def __init__( self, expr ):
+        super(ZeroOrMore,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        tokens = []
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
+            while 1:
+                if hasIgnoreExprs:
+                    preloc = self._skipIgnorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.keys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]..."
+
+        return self.strRepr
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
+        ret.saveAsList = True
+        return ret
+
+
+class OneOrMore(ParseElementEnhance):
+    """Repetition of one or more of the given expression."""
+    def parseImpl( self, instring, loc, doActions=True ):
+        # must be at least one
+        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        try:
+            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
+            while 1:
+                if hasIgnoreExprs:
+                    preloc = self._skipIgnorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.keys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + _ustr(self.expr) + "}..."
+
+        return self.strRepr
+
+    def setResultsName( self, name, listAllMatches=False ):
+        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
+        ret.saveAsList = True
+        return ret
+
+class _NullToken(object):
+    def __bool__(self):
+        return False
+    __nonzero__ = __bool__
+    def __str__(self):
+        return ""
+
+_optionalNotMatched = _NullToken()
+class Optional(ParseElementEnhance):
+    """Optional matching of the given expression.
+       A default return string can also be specified, if the optional expression
+       is not found.
+    """
+    def __init__( self, exprs, default=_optionalNotMatched ):
+        super(Optional,self).__init__( exprs, savelist=False )
+        self.defaultValue = default
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        except (ParseException,IndexError):
+            if self.defaultValue is not _optionalNotMatched:
+                if self.expr.resultsName:
+                    tokens = ParseResults([ self.defaultValue ])
+                    tokens[self.expr.resultsName] = self.defaultValue
+                else:
+                    tokens = [ self.defaultValue ]
+            else:
+                tokens = []
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]"
+
+        return self.strRepr
+
+
+class SkipTo(ParseElementEnhance):
+    """Token for skipping over all undefined text until the matched expression is found.
+       If include is set to true, the matched expression is also parsed (the skipped text
+       and matched expression are returned as a 2-element list).  The ignore
+       argument is used to define grammars (typically quoted strings and comments) that
+       might contain false matches.
+    """
+    def __init__( self, other, include=False, ignore=None, failOn=None ):
+        super( SkipTo, self ).__init__( other )
+        self.ignoreExpr = ignore
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.includeMatch = include
+        self.asList = False
+        if failOn is not None and isinstance(failOn, basestring):
+            self.failOn = Literal(failOn)
+        else:
+            self.failOn = failOn
+        self.errmsg = "No match found for "+_ustr(self.expr)
+        #self.myException = ParseException("",0,self.errmsg,self)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        startLoc = loc
+        instrlen = len(instring)
+        expr = self.expr
+        failParse = False
+        while loc <= instrlen:
+            try:
+                if self.failOn:
+                    try:
+                        self.failOn.tryParse(instring, loc)
+                    except ParseBaseException:
+                        pass
+                    else:
+                        failParse = True
+                        raise ParseException(instring, loc, "Found expression " + str(self.failOn))
+                    failParse = False
+                if self.ignoreExpr is not None:
+                    while 1:
+                        try:
+                            loc = self.ignoreExpr.tryParse(instring,loc)
+                            # print("found ignoreExpr, advance to", loc)
+                        except ParseBaseException:
+                            break
+                expr._parse( instring, loc, doActions=False, callPreParse=False )
+                skipText = instring[startLoc:loc]
+                if self.includeMatch:
+                    loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
+                    if mat:
+                        skipRes = ParseResults( skipText )
+                        skipRes += mat
+                        return loc, [ skipRes ]
+                    else:
+                        return loc, [ skipText ]
+                else:
+                    return loc, [ skipText ]
+            except (ParseException,IndexError):
+                if failParse:
+                    raise
+                else:
+                    loc += 1
+        exc = self.myException
+        exc.loc = loc
+        exc.pstr = instring
+        raise exc
+
+class Forward(ParseElementEnhance):
+    """Forward declaration of an expression to be defined later -
+       used for recursive grammars, such as algebraic infix notation.
+       When the expression is known, it is assigned to the Forward variable using the '<<' operator.
+
+       Note: take care when assigning to Forward not to overlook precedence of operators.
+       Specifically, '|' has a lower precedence than '<<', so that::
+          fwdExpr << a | b | c
+       will actually be evaluated as::
+          (fwdExpr << a) | b | c
+       thereby leaving b and c out as parseable alternatives.  It is recommended that you
+       explicitly group the values inserted into the Forward::
+          fwdExpr << (a | b | c)
+    """
+    def __init__( self, other=None ):
+        super(Forward,self).__init__( other, savelist=False )
+
+    def __lshift__( self, other ):
+        if isinstance( other, basestring ):
+            other = Literal(other)
+        self.expr = other
+        self.mayReturnEmpty = other.mayReturnEmpty
+        self.strRepr = None
+        self.mayIndexError = self.expr.mayIndexError
+        self.mayReturnEmpty = self.expr.mayReturnEmpty
+        self.setWhitespaceChars( self.expr.whiteChars )
+        self.skipWhitespace = self.expr.skipWhitespace
+        self.saveAsList = self.expr.saveAsList
+        self.ignoreExprs.extend(self.expr.ignoreExprs)
+        return None
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        return self
+
+    def streamline( self ):
+        if not self.streamlined:
+            self.streamlined = True
+            if self.expr is not None:
+                self.expr.streamline()
+        return self
+
+    def validate( self, validateTrace=[] ):
+        if self not in validateTrace:
+            tmp = validateTrace[:]+[self]
+            if self.expr is not None:
+                self.expr.validate(tmp)
+        self.checkRecursion([])
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        self._revertClass = self.__class__
+        self.__class__ = _ForwardNoRecurse
+        try:
+            if self.expr is not None:
+                retString = _ustr(self.expr)
+            else:
+                retString = "None"
+        finally:
+            self.__class__ = self._revertClass
+        return self.__class__.__name__ + ": " + retString
+
+    def copy(self):
+        if self.expr is not None:
+            return super(Forward,self).copy()
+        else:
+            ret = Forward()
+            ret << self
+            return ret
+
+class _ForwardNoRecurse(Forward):
+    def __str__( self ):
+        return "..."
+
+class TokenConverter(ParseElementEnhance):
+    """Abstract subclass of ParseExpression, for converting parsed results."""
+    def __init__( self, expr, savelist=False ):
+        super(TokenConverter,self).__init__( expr )#, savelist )
+        self.saveAsList = False
+
+class Upcase(TokenConverter):
+    """Converter to upper case all matching tokens."""
+    def __init__(self, *args):
+        super(Upcase,self).__init__(*args)
+        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
+                       DeprecationWarning,stacklevel=2)
+
+    def postParse( self, instring, loc, tokenlist ):
+        return list(map( string.upper, tokenlist ))
+
+
+class Combine(TokenConverter):
+    """Converter to concatenate all matching tokens to a single string.
+       By default, the matching patterns must also be contiguous in the input string;
+       this can be disabled by specifying 'adjacent=False' in the constructor.
+    """
+    def __init__( self, expr, joinString="", adjacent=True ):
+        super(Combine,self).__init__( expr )
+        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
+        if adjacent:
+            self.leaveWhitespace()
+        self.adjacent = adjacent
+        self.skipWhitespace = True
+        self.joinString = joinString
+
+    def ignore( self, other ):
+        if self.adjacent:
+            ParserElement.ignore(self, other)
+        else:
+            super( Combine, self).ignore( other )
+        return self
+
+    def postParse( self, instring, loc, tokenlist ):
+        retToks = tokenlist.copy()
+        del retToks[:]
+        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
+
+        if self.resultsName and len(retToks.keys())>0:
+            return [ retToks ]
+        else:
+            return retToks
+
+class Group(TokenConverter):
+    """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions."""
+    def __init__( self, expr ):
+        super(Group,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        return [ tokenlist ]
+
+class Dict(TokenConverter):
+    """Converter to return a repetitive expression as a list, but also as a dictionary.
+       Each element can also be referenced using the first token in the expression as its key.
+       Useful for tabular report scraping when the first column can be used as a item key.
+    """
+    def __init__( self, exprs ):
+        super(Dict,self).__init__( exprs )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        for i,tok in enumerate(tokenlist):
+            if len(tok) == 0:
+                continue
+            ikey = tok[0]
+            if isinstance(ikey,int):
+                ikey = _ustr(tok[0]).strip()
+            if len(tok)==1:
+                tokenlist[ikey] = _ParseResultsWithOffset("",i)
+            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
+                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
+            else:
+                dictvalue = tok.copy() #ParseResults(i)
+                del dictvalue[0]
+                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
+                else:
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
+
+        if self.resultsName:
+            return [ tokenlist ]
+        else:
+            return tokenlist
+
+
+class Suppress(TokenConverter):
+    """Converter for ignoring the results of a parsed expression."""
+    def postParse( self, instring, loc, tokenlist ):
+        return []
+
+    def suppress( self ):
+        return self
+
+
+class OnlyOnce(object):
+    """Wrapper for parse actions, to ensure they are only called once."""
+    def __init__(self, methodCall):
+        self.callable = ParserElement._normalizeParseActionArgs(methodCall)
+        self.called = False
+    def __call__(self,s,l,t):
+        if not self.called:
+            results = self.callable(s,l,t)
+            self.called = True
+            return results
+        raise ParseException(s,l,"")
+    def reset(self):
+        self.called = False
+
+def traceParseAction(f):
+    """Decorator for debugging parse actions."""
+    f = ParserElement._normalizeParseActionArgs(f)
+    def z(*paArgs):
+        thisFunc = f.func_name
+        s,l,t = paArgs[-3:]
+        if len(paArgs)>3:
+            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
+        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
+        try:
+            ret = f(*paArgs)
+        except Exception:
+            exc = sys.exc_info()[1]
+            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
+            raise
+        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
+        return ret
+    try:
+        z.__name__ = f.__name__
+    except AttributeError:
+        pass
+    return z
+
+#
+# global helpers
+#
+def delimitedList( expr, delim=",", combine=False ):
+    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
+       By default, the list elements and delimiters can have intervening whitespace, and
+       comments, but this can be overridden by passing 'combine=True' in the constructor.
+       If combine is set to True, the matching tokens are returned as a single token
+       string, with the delimiters included; otherwise, the matching tokens are returned
+       as a list of tokens, with the delimiters suppressed.
+    """
+    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
+    if combine:
+        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
+    else:
+        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
+
+def countedArray( expr ):
+    """Helper to define a counted list of expressions.
+       This helper defines a pattern of the form::
+           integer expr expr expr...
+       where the leading integer tells how many expr expressions follow.
+       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
+    """
+    arrayExpr = Forward()
+    def countFieldParseAction(s,l,t):
+        n = int(t[0])
+        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
+        return []
+    return ( Word(nums).setName("arrayLen").setParseAction(countFieldParseAction, callDuringTry=True) + arrayExpr )
+
+def _flatten(L):
+    if type(L) is not list: return [L]
+    if L == []: return L
+    return _flatten(L[0]) + _flatten(L[1:])
+
+def matchPreviousLiteral(expr):
+    """Helper to define an expression that is indirectly defined from
+       the tokens matched in a previous expression, that is, it looks
+       for a 'repeat' of a previous expression.  For example::
+           first = Word(nums)
+           second = matchPreviousLiteral(first)
+           matchExpr = first + ":" + second
+       will match "1:1", but not "1:2".  Because this matches a
+       previous literal, will also match the leading "1:1" in "1:10".
+       If this is not desired, use matchPreviousExpr.
+       Do *not* use with packrat parsing enabled.
+    """
+    rep = Forward()
+    def copyTokenToRepeater(s,l,t):
+        if t:
+            if len(t) == 1:
+                rep << t[0]
+            else:
+                # flatten t tokens
+                tflat = _flatten(t.asList())
+                rep << And( [ Literal(tt) for tt in tflat ] )
+        else:
+            rep << Empty()
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    return rep
+
+def matchPreviousExpr(expr):
+    """Helper to define an expression that is indirectly defined from
+       the tokens matched in a previous expression, that is, it looks
+       for a 'repeat' of a previous expression.  For example::
+           first = Word(nums)
+           second = matchPreviousExpr(first)
+           matchExpr = first + ":" + second
+       will match "1:1", but not "1:2".  Because this matches by
+       expressions, will *not* match the leading "1:1" in "1:10";
+       the expressions are evaluated first, and then compared, so
+       "1" is compared with "10".
+       Do *not* use with packrat parsing enabled.
+    """
+    rep = Forward()
+    e2 = expr.copy()
+    rep << e2
+    def copyTokenToRepeater(s,l,t):
+        matchTokens = _flatten(t.asList())
+        def mustMatchTheseTokens(s,l,t):
+            theseTokens = _flatten(t.asList())
+            if  theseTokens != matchTokens:
+                raise ParseException("",0,"")
+        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    return rep
+
+def _escapeRegexRangeChars(s):
+    #~  escape these chars: ^-]
+    for c in r"\^-]":
+        s = s.replace(c,_bslash+c)
+    s = s.replace("\n",r"\n")
+    s = s.replace("\t",r"\t")
+    return _ustr(s)
+
+def oneOf( strs, caseless=False, useRegex=True ):
+    """Helper to quickly define a set of alternative Literals, and makes sure to do
+       longest-first testing when there is a conflict, regardless of the input order,
+       but returns a MatchFirst for best performance.
+
+       Parameters:
+        - strs - a string of space-delimited literals, or a list of string literals
+        - caseless - (default=False) - treat all literals as caseless
+        - useRegex - (default=True) - as an optimization, will generate a Regex
+          object; otherwise, will generate a MatchFirst object (if caseless=True, or
+          if creating a Regex raises an exception)
+    """
+    if caseless:
+        isequal = ( lambda a,b: a.upper() == b.upper() )
+        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
+        parseElementClass = CaselessLiteral
+    else:
+        isequal = ( lambda a,b: a == b )
+        masks = ( lambda a,b: b.startswith(a) )
+        parseElementClass = Literal
+
+    if isinstance(strs,(list,tuple)):
+        symbols = list(strs[:])
+    elif isinstance(strs,basestring):
+        symbols = strs.split()
+    else:
+        warnings.warn("Invalid argument to oneOf, expected string or list",
+                SyntaxWarning, stacklevel=2)
+
+    i = 0
+    while i < len(symbols)-1:
+        cur = symbols[i]
+        for j,other in enumerate(symbols[i+1:]):
+            if ( isequal(other, cur) ):
+                del symbols[i+j+1]
+                break
+            elif ( masks(cur, other) ):
+                del symbols[i+j+1]
+                symbols.insert(i,other)
+                cur = other
+                break
+        else:
+            i += 1
+
+    if not caseless and useRegex:
+        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
+        try:
+            if len(symbols)==len("".join(symbols)):
+                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
+            else:
+                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
+        except:
+            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
+                    SyntaxWarning, stacklevel=2)
+
+
+    # last resort, just use MatchFirst
+    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
+
+def dictOf( key, value ):
+    """Helper to easily and clearly define a dictionary by specifying the respective patterns
+       for the key and value.  Takes care of defining the Dict, ZeroOrMore, and Group tokens
+       in the proper order.  The key pattern can include delimiting markers or punctuation,
+       as long as they are suppressed, thereby leaving the significant key text.  The value
+       pattern can include named results, so that the Dict results can include named token
+       fields.
+    """
+    return Dict( ZeroOrMore( Group ( key + value ) ) )
+
+def originalTextFor(expr, asString=True):
+    """Helper to return the original, untokenized text for a given expression.  Useful to
+       restore the parsed fields of an HTML start tag into the raw tag text itself, or to
+       revert separate tokens with intervening whitespace back to the original matching
+       input text. Simpler to use than the parse action keepOriginalText, and does not
+       require the inspect module to chase up the call stack.  By default, returns a 
+       string containing the original parsed text.  
+       
+       If the optional asString argument is passed as False, then the return value is a 
+       ParseResults containing any results names that were originally matched, and a 
+       single token containing the original matched text from the input string.  So if 
+       the expression passed to originalTextFor contains expressions with defined
+       results names, you must set asString to False if you want to preserve those
+       results name values."""
+    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
+    matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
+    if asString:
+        extractText = lambda s,l,t: s[t._original_start:t._original_end]
+    else:
+        def extractText(s,l,t):
+            del t[:]
+            t.insert(0, s[t._original_start:t._original_end])
+            del t["_original_start"]
+            del t["_original_end"]
+    matchExpr.setParseAction(extractText)
+    return matchExpr
+    
+# convenience constants for positional expressions
+empty       = Empty().setName("empty")
+lineStart   = LineStart().setName("lineStart")
+lineEnd     = LineEnd().setName("lineEnd")
+stringStart = StringStart().setName("stringStart")
+stringEnd   = StringEnd().setName("stringEnd")
+
+_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
+_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
+_escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
+_escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
+_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
+_charRange = Group(_singleChar + Suppress("-") + _singleChar)
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
+
+_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
+
+def srange(s):
+    r"""Helper to easily define string ranges for use in Word construction.  Borrows
+       syntax from regexp '[]' string range definitions::
+          srange("[0-9]")   -> "0123456789"
+          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
+          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
+       The input string must be enclosed in []'s, and the returned string is the expanded
+       character set joined into a single string.
+       The values enclosed in the []'s may be::
+          a single character
+          an escaped character with a leading backslash (such as \- or \])
+          an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
+          an escaped octal character with a leading '\0' (\041, which is a '!' character)
+          a range of any of the above, separated by a dash ('a-z', etc.)
+          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
+    """
+    try:
+        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
+    except:
+        return ""
+
+def matchOnlyAtCol(n):
+    """Helper method for defining parse actions that require matching at a specific
+       column in the input text.
+    """
+    def verifyCol(strg,locn,toks):
+        if col(locn,strg) != n:
+            raise ParseException(strg,locn,"matched token not at column %d" % n)
+    return verifyCol
+
+def replaceWith(replStr):
+    """Helper method for common parse actions that simply return a literal value.  Especially
+       useful when used with transformString().
+    """
+    def _replFunc(*args):
+        return [replStr]
+    return _replFunc
+
+def removeQuotes(s,l,t):
+    """Helper parse action for removing quotation marks from parsed quoted strings.
+       To use, add this parse action to quoted string using::
+         quotedString.setParseAction( removeQuotes )
+    """
+    return t[0][1:-1]
+
+def upcaseTokens(s,l,t):
+    """Helper parse action to convert tokens to upper case."""
+    return [ tt.upper() for tt in map(_ustr,t) ]
+
+def downcaseTokens(s,l,t):
+    """Helper parse action to convert tokens to lower case."""
+    return [ tt.lower() for tt in map(_ustr,t) ]
+
+def keepOriginalText(s,startLoc,t):
+    """Helper parse action to preserve original parsed text,
+       overriding any nested parse actions."""
+    try:
+        endloc = getTokensEndLoc()
+    except ParseException:
+        raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
+    del t[:]
+    t += ParseResults(s[startLoc:endloc])
+    return t
+
+def getTokensEndLoc():
+    """Method to be called from within a parse action to determine the end
+       location of the parsed tokens."""
+    import inspect
+    fstack = inspect.stack()
+    try:
+        # search up the stack (through intervening argument normalizers) for correct calling routine
+        for f in fstack[2:]:
+            if f[3] == "_parseNoCache":
+                endloc = f[0].f_locals["loc"]
+                return endloc
+        else:
+            raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
+    finally:
+        del fstack
+
+def _makeTags(tagStr, xml):
+    """Internal helper to construct opening and closing tag expressions, given a tag name"""
+    if isinstance(tagStr,basestring):
+        resname = tagStr
+        tagStr = Keyword(tagStr, caseless=not xml)
+    else:
+        resname = tagStr.name
+
+    tagAttrName = Word(alphas,alphanums+"_-:")
+    if (xml):
+        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
+        openTag = Suppress("<") + tagStr + \
+                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    else:
+        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
+        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
+        openTag = Suppress("<") + tagStr + \
+                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
+                Optional( Suppress("=") + tagAttrValue ) ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    closeTag = Combine(_L("</") + tagStr + ">")
+
+    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
+    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
+
+    return openTag, closeTag
+
+def makeHTMLTags(tagStr):
+    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
+    return _makeTags( tagStr, False )
+
+def makeXMLTags(tagStr):
+    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
+    return _makeTags( tagStr, True )
+
+def withAttribute(*args,**attrDict):
+    """Helper to create a validating parse action to be used with start tags created
+       with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag
+       with a required attribute value, to avoid false matches on common tags such as
+       <TD> or <DIV>.
+
+       Call withAttribute with a series of attribute names and values. Specify the list
+       of filter attributes names and values as:
+        - keyword arguments, as in (class="Customer",align="right"), or
+        - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
+       For attribute names with a namespace prefix, you must use the second form.  Attribute
+       names are matched insensitive to upper/lower case.
+
+       To verify that the attribute exists, but without specifying a value, pass
+       withAttribute.ANY_VALUE as the value.
+       """
+    if args:
+        attrs = args[:]
+    else:
+        attrs = attrDict.items()
+    attrs = [(k,v) for k,v in attrs]
+    def pa(s,l,tokens):
+        for attrName,attrValue in attrs:
+            if attrName not in tokens:
+                raise ParseException(s,l,"no matching attribute " + attrName)
+            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
+                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
+                                            (attrName, tokens[attrName], attrValue))
+    return pa
+withAttribute.ANY_VALUE = object()
+
+opAssoc = _Constants()
+opAssoc.LEFT = object()
+opAssoc.RIGHT = object()
+
+def operatorPrecedence( baseExpr, opList ):
+    """Helper method for constructing grammars of expressions made up of
+       operators working in a precedence hierarchy.  Operators may be unary or
+       binary, left- or right-associative.  Parse actions can also be attached
+       to operator expressions.
+
+       Parameters:
+        - baseExpr - expression representing the most basic element for the nested
+        - opList - list of tuples, one for each operator precedence level in the
+          expression grammar; each tuple is of the form
+          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
+           - opExpr is the pyparsing expression for the operator;
+              may also be a string, which will be converted to a Literal;
+              if numTerms is 3, opExpr is a tuple of two expressions, for the
+              two operators separating the 3 terms
+           - numTerms is the number of terms for this operator (must
+              be 1, 2, or 3)
+           - rightLeftAssoc is the indicator whether the operator is
+              right or left associative, using the pyparsing-defined
+              constants opAssoc.RIGHT and opAssoc.LEFT.
+           - parseAction is the parse action to be associated with
+              expressions matching this operator expression (the
+              parse action tuple member may be omitted)
+    """
+    ret = Forward()
+    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
+    for i,operDef in enumerate(opList):
+        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
+        if arity == 3:
+            if opExpr is None or len(opExpr) != 2:
+                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
+            opExpr1, opExpr2 = opExpr
+        thisExpr = Forward()#.setName("expr%d" % i)
+        if rightLeftAssoc == opAssoc.LEFT:
+            if arity == 1:
+                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
+                else:
+                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
+            elif arity == 3:
+                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
+                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        elif rightLeftAssoc == opAssoc.RIGHT:
+            if arity == 1:
+                # try to avoid LR with this extra test
+                if not isinstance(opExpr, Optional):
+                    opExpr = Optional(opExpr)
+                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
+                else:
+                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
+            elif arity == 3:
+                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
+                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        else:
+            raise ValueError("operator must indicate right or left associativity")
+        if pa:
+            matchExpr.setParseAction( pa )
+        thisExpr << ( matchExpr | lastExpr )
+        lastExpr = thisExpr
+    ret << lastExpr
+    return ret
+
+dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
+sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
+quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
+unicodeString = Combine(_L('u') + quotedString.copy())
+
+def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):
+    """Helper method for defining nested lists enclosed in opening and closing
+       delimiters ("(" and ")" are the default).
+
+       Parameters:
+        - opener - opening character for a nested list (default="("); can also be a pyparsing expression
+        - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
+        - content - expression for items within the nested lists (default=None)
+        - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
+
+       If an expression is not provided for the content argument, the nested
+       expression will capture all whitespace-delimited content between delimiters
+       as a list of separate values.
+
+       Use the ignoreExpr argument to define expressions that may contain
+       opening or closing characters that should not be treated as opening
+       or closing characters for nesting, such as quotedString or a comment
+       expression.  Specify multiple expressions using an Or or MatchFirst.
+       The default is quotedString, but if no expressions are to be ignored,
+       then pass None for this argument.
+    """
+    if opener == closer:
+        raise ValueError("opening and closing strings cannot be the same")
+    if content is None:
+        if isinstance(opener,basestring) and isinstance(closer,basestring):
+            if len(opener) == 1 and len(closer)==1:
+                if ignoreExpr is not None:
+                    content = (Combine(OneOrMore(~ignoreExpr +
+                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+                else:
+                    content = (empty+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
+                                ).setParseAction(lambda t:t[0].strip()))
+            else:
+                if ignoreExpr is not None:
+                    content = (Combine(OneOrMore(~ignoreExpr + 
+                                    ~Literal(opener) + ~Literal(closer) +
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+                else:
+                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
+                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
+                                ).setParseAction(lambda t:t[0].strip()))
+        else:
+            raise ValueError("opening and closing arguments must be strings if no content expression is given")
+    ret = Forward()
+    if ignoreExpr is not None:
+        ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
+    else:
+        ret << Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )
+    return ret
+
+def indentedBlock(blockStatementExpr, indentStack, indent=True):
+    """Helper method for defining space-delimited indentation blocks, such as
+       those used to define block statements in Python source code.
+
+       Parameters:
+        - blockStatementExpr - expression defining syntax of statement that
+            is repeated within the indented block
+        - indentStack - list created by caller to manage indentation stack
+            (multiple statementWithIndentedBlock expressions within a single grammar
+            should share a common indentStack)
+        - indent - boolean indicating whether block must be indented beyond the
+            the current level; set to False for block of left-most statements
+            (default=True)
+
+       A valid block must contain at least one blockStatement.
+    """
+    def checkPeerIndent(s,l,t):
+        if l >= len(s): return
+        curCol = col(l,s)
+        if curCol != indentStack[-1]:
+            if curCol > indentStack[-1]:
+                raise ParseFatalException(s,l,"illegal nesting")
+            raise ParseException(s,l,"not a peer entry")
+
+    def checkSubIndent(s,l,t):
+        curCol = col(l,s)
+        if curCol > indentStack[-1]:
+            indentStack.append( curCol )
+        else:
+            raise ParseException(s,l,"not a subentry")
+
+    def checkUnindent(s,l,t):
+        if l >= len(s): return
+        curCol = col(l,s)
+        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
+            raise ParseException(s,l,"not an unindent")
+        indentStack.pop()
+
+    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
+    INDENT = Empty() + Empty().setParseAction(checkSubIndent)
+    PEER   = Empty().setParseAction(checkPeerIndent)
+    UNDENT = Empty().setParseAction(checkUnindent)
+    if indent:
+        smExpr = Group( Optional(NL) +
+            FollowedBy(blockStatementExpr) +
+            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
+    else:
+        smExpr = Group( Optional(NL) +
+            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
+    blockStatementExpr.ignore(_bslash + LineEnd())
+    return smExpr
+
+alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
+punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
+
+anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
+commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
+_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
+replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
+
+# it's easy to get these comment structures wrong - they're very common, so may as well make them available
+cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
+
+htmlComment = Regex(r"<!--[\s\S]*?-->")
+restOfLine = Regex(r".*").leaveWhitespace()
+dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
+cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
+
+javaStyleComment = cppStyleComment
+pythonStyleComment = Regex(r"#.*").setName("Python style comment")
+_noncomma = "".join( [ c for c in printables if c != "," ] )
+_commasepitem = Combine(OneOrMore(Word(_noncomma) +
+                                  Optional( Word(" \t") +
+                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
+commaSeparatedList = delimitedList( Optional( quotedString | _commasepitem, default="") ).setName("commaSeparatedList")
+
+
+if __name__ == "__main__":
+
+    def test( teststring ):
+        try:
+            tokens = simpleSQL.parseString( teststring )
+            tokenlist = tokens.asList()
+            print (teststring + "->"   + str(tokenlist))
+            print ("tokens = "         + str(tokens))
+            print ("tokens.columns = " + str(tokens.columns))
+            print ("tokens.tables = "  + str(tokens.tables))
+            print (tokens.asXML("SQL",True))
+        except ParseBaseException:
+            err = sys.exc_info()[1]
+            print (teststring + "->")
+            print (err.line)
+            print (" "*(err.column-1) + "^")
+            print (err)
+        print()
+
+    selectToken    = CaselessLiteral( "select" )
+    fromToken      = CaselessLiteral( "from" )
+
+    ident          = Word( alphas, alphanums + "_$" )
+    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
+    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
+    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
+    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
+    simpleSQL      = ( selectToken + \
+                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
+                     fromToken + \
+                     tableNameList.setResultsName( "tables" ) )
+
+    test( "SELECT * from XYZZY, ABC" )
+    test( "select * from SYS.XYZZY" )
+    test( "Select A from Sys.dual" )
+    test( "Select AA,BB,CC from Sys.dual" )
+    test( "Select A, B, C from Sys.dual" )
+    test( "Select A, B, C from Sys.dual" )
+    test( "Xelect A, B, C from Sys.dual" )
+    test( "Select A, B, C frox Sys.dual" )
+    test( "Select" )
+    test( "Select ^^^ frox Sys.dual" )
+    test( "Select A, B, C from Sys.dual, Table2   " )
diff --git a/setup.py b/setup.py
new file mode 100644
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""Setup script for the pyparsing module distribution."""
+from distutils.core import setup
+
+from pyparsing import __version__
+
+setup(# Distribution meta-data
+    name = "pyparsing",
+    version = __version__,
+    description = "Python parsing module",
+    author = "Paul McGuire",
+    author_email = "ptmcg@users.sourceforge.net",
+    url = "http://pyparsing.wikispaces.com/",
+    download_url = "http://sourceforge.net/project/showfiles.php?group_id=97203",
+    license = "MIT License",
+    py_modules = ["pyparsing"],
+    classifiers=[
+        'Development Status :: 5 - Production/Stable',
+        'Intended Audience :: Developers',
+        'Intended Audience :: Information Technology',
+        'License :: OSI Approved :: MIT License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        ]
+    )
diff --git a/src/CHANGES b/src/CHANGES
deleted file mode 100644
--- a/src/CHANGES
+++ /dev/null
@@ -1,1668 +0,0 @@
-==========
-Change Log
-==========
-
-Version 1.5.7 - 
------------------
-- An awesome new example is included in this release, submitted
-  by Luca DellOlio, for parsing ANTLR grammar definitions, nice
-  work Luca!
-
-- Fixed implementation of ParseResults.__str__ to use Pythonic
-  ''.join() instead of repeated string concatenation. This
-  purportedly has been a performance issue under PyPy.
-
-- Fixed bug in ParseResults.__dir__ under Python 3, reported by
-  Thomas Kluyver, thank you Thomas!
-
-- Added ParserElement.inlineLiteralsUsing static method, to 
-  override pyparsing's default behavior of converting string
-  literals to Literal instances, to use other classes (such
-  as Suppress or CaselessLiteral).
-
-- Added new operator '<<=', which will eventually replace '<<' for 
-  storing the contents of a Forward(). '<<=' does not have the same
-  operator precedence problems that '<<' does.
-
-- Added support for using single argument builtin functions as parse 
-  actions.  Now you can write 'expr.setParseAction(len)' and get back
-  the length of the list of matched tokens.  Supported builtins are:
-  sum, len, sorted, reversed, list, tuple, set, any, all, min, and max.
-
-- Improved linking in generated docs, proposed on the pyparsing wiki
-  by techtonik, thanks!
-
-- Fixed a bug in the definition of 'alphas', which was based on the 
-  string.uppercase and string.lowercase "constants", which in fact 
-  *aren't* constant, but vary with locale settings. This could make 
-  parsers locale-sensitive in a subtle way. Thanks to Kef Schecter for
-  his diligence in following through on reporting and monitoring 
-  this bugfix!
-
-- Fixed a bug in the Py3 version of pyparsing, during exception
-  handling with packrat parsing enabled, reported by Catherine 
-  Devlin - thanks Catherine!
-
-- Fixed typo in ParseBaseException.__dir__, reported anonymously on 
-  the SourceForge bug tracker, thank you Pyparsing User With No Name.
-
-- Fixed bug in srange when using '\x###' hex character codes.
-
-- Addeed optional 'intExpr' argument to countedArray, so that you 
-  can define your own expression that will evaluate to an integer,
-  to be used as the count for the following elements. Allows you 
-  to define a countedArray with the count given in hex, for example,
-  by defining intExpr as "Word(hexnums).setParseAction(int(t[0],16))".
-
-
-Version 1.5.6 - June, 2011
-----------------------------
-- Cleanup of parse action normalizing code, to be more version-tolerant,
-  and robust in the face of future Python versions - much thanks to 
-  Raymond Hettinger for this rewrite!
-
-- Removal of exception cacheing, addressing a memory leak condition
-  in Python 3. Thanks to Michael Droettboom and the Cape Town PUG for
-  their analysis and work on this problem!
-
-- Fixed bug when using packrat parsing, where a previously parsed
-  expression would duplicate subsequent tokens - reported by Frankie 
-  Ribery on stackoverflow, thanks!
-
-- Added 'ungroup' helper method, to address token grouping done
-  implicitly by And expressions, even if only one expression in the
-  And actually returns any text - also inspired by stackoverflow
-  discussion with Frankie Ribery!
-
-- Fixed bug in srange, which accepted escaped hex characters of the 
-  form '\0x##', but should be '\x##'.  Both forms will be supported
-  for backwards compatibility.
-
-- Enhancement to countedArray, accepting an optional expression to be
-  used for matching the leading integer count - proposed by Mathias on
-  the pyparsing mailing list, good idea!
-
-- Added the Verilog parser to the provided set of examples, under the
-  MIT license.  While this frees up this parser for any use, if you find
-  yourself using it in a commercial purpose, please consider making a
-  charitable donation as described in the parser's header.
-
-- Added the excludeChars argument to the Word class, to simplify defining
-  a word composed of all characters in a large range except for one or
-  two. Suggested by JesterEE on the pyparsing wiki.
-
-- Added optional overlap parameter to scanString, to return overlapping
-  matches found in the source text.
-
-- Updated oneOf internal regular expression generation, with improved
-  parse time performance.
-  
-- Slight performance improvement in transformString, removing empty
-  strings from the list of string fragments built while scanning the
-  source text, before calling ''.join.  Especially useful when using 
-  transformString to strip out selected text.
-
-- Enhanced form of using the "expr('name')" style of results naming,
-  in lieu of calling setResultsName.  If name ends with an '*', then
-  this is equivalent to expr.setResultsName('name',listAllMatches=True).
-
-- Fixed up internal list flattener to use iteration instead of recursion,
-  to avoid stack overflow when transforming large files.
-
-- Added other new examples:
-  . protobuf parser - parses Google's protobuf language
-  . btpyparse - a BibTex parser contributed by Matthew Brett,
-    with test suite test_bibparse.py (thanks, Matthew!)
-  . groupUsingListAllMatches.py - demo using trailing '*' for results 
-    names
-
-
-Version 1.5.5 - August, 2010
-----------------------------
-
-- Typo in Python3 version of pyparsing, "builtin" should be "builtins".
-  (sigh)
-
-
-Version 1.5.4 - August, 2010
-----------------------------
-
-- Fixed __builtins__ and file references in Python 3 code, thanks to 
-  Greg Watson, saulspatz, sminos, and Mark Summerfield for reporting 
-  their Python 3 experiences.
-
-- Added new example, apicheck.py, as a sample of scanning a Tcl-like
-  language for functions with incorrect number of arguments (difficult
-  to track down in Tcl languages).  This example uses some interesting
-  methods for capturing exceptions while scanning through source
-  code.
-
-- Added new example deltaTime.py, that takes everyday time references
-  like "an hour from now", "2 days ago", "next Sunday at 2pm".
-
-
-Version 1.5.3 - June, 2010
---------------------------
-
-- ======= NOTE:  API CHANGE!!!!!!! ===============
-  With this release, and henceforward, the pyparsing module is 
-  imported as "pyparsing" on both Python 2.x and Python 3.x versions.
-
-- Fixed up setup.py to auto-detect Python version and install the 
-  correct version of pyparsing - suggested by Alex Martelli, 
-  thanks, Alex! (and my apologies to all those who struggled with 
-  those spurious installation errors caused by my earlier 
-  fumblings!)
-
-- Fixed bug on Python3 when using parseFile, getting bytes instead of
-  a str from the input file.
-
-- Fixed subtle bug in originalTextFor, if followed by
-  significant whitespace (like a newline) - discovered by
-  Francis Vidal, thanks!
-
-- Fixed very sneaky bug in Each, in which Optional elements were
-  not completely recognized as optional - found by Tal Weiss, thanks
-  for your patience.
-  
-- Fixed off-by-1 bug in line() method when the first line of the
-  input text was an empty line. Thanks to John Krukoff for submitting
-  a patch!
-  
-- Fixed bug in transformString if grammar contains Group expressions,
-  thanks to patch submitted by barnabas79, nice work!
-  
-- Fixed bug in originalTextFor in which trailing comments or otherwised
-  ignored text got slurped in with the matched expression.  Thanks to
-  michael_ramirez44 on the pyparsing wiki for reporting this just in
-  time to get into this release!
-
-- Added better support for summing ParseResults, see the new example,
-  parseResultsSumExample.py.
-  
-- Added support for composing a Regex using a compiled RE object; 
-  thanks to my new colleague, Mike Thornton!
-
-- In version 1.5.2, I changed the way exceptions are raised in order
-  to simplify the stacktraces reported during parsing.  An anonymous
-  user posted a bug report on SF that this behavior makes it difficult
-  to debug some complex parsers, or parsers nested within parsers. In
-  this release I've added a class attribute ParserElement.verbose_stacktrace,
-  with a default value of False. If you set this to True, pyparsing will 
-  report stacktraces using the pre-1.5.2 behavior.
-
-- New examples: 
-
-  . pymicko.py, a MicroC compiler submitted by Zarko Zivanov. 
-    (Note: this example is separately licensed under the GPLv3, 
-    and requires Python 2.6 or higher.)  Thank you, Zarko!
-
-  . oc.py, a subset C parser, using the BNF from the 1996 Obfuscated C
-    Contest.
-
-  . stateMachine2.py, a modified version of stateMachine.py submitted 
-    by Matt Anderson, that is compatible with Python versions 2.7 and 
-    above - thanks so much, Matt!
-    
-  . select_parser.py, a parser for reading SQLite SELECT statements, 
-    as specified at http://www.sqlite.org/lang_select.html; this goes
-    into much more detail than the simple SQL parser included in pyparsing's
-    source code
-    
-  . excelExpr.py, a *simplistic* first-cut at a parser for Excel 
-    expressions, which I originally posted on comp.lang.python in January, 
-    2010; beware, this parser omits many common Excel cases (addition of
-    numbers represented as strings, references to named ranges)
-    
-  . cpp_enum_parser.py, a nice little parser posted my Mark Tolonen on
-    comp.lang.python in August, 2009 (redistributed here with Mark's
-    permission).  Thanks a bunch, Mark!
-    
-  . partial_gene_match.py, a sample I posted to Stackoverflow.com,
-    implementing a special variation on Literal that does "close" matching,
-    up to a given number of allowed mismatches.  The application was to 
-    find matching gene sequences, with allowance for one or two mismatches.
-    
-  . tagCapture.py, a sample showing how to use a Forward placeholder to
-    enforce matching of text parsed in a previous expression.
-
-  . matchPreviousDemo.py, simple demo showing how the matchPreviousLiteral
-    helper method is used to match a previously parsed token.
-
-
-Version 1.5.2 - April, 2009
-------------------------------
-- Added pyparsing_py3.py module, so that Python 3 users can use
-  pyparsing by changing their pyparsing import statement to:
-  
-      import pyparsing_py3
-
-  Thanks for help from Patrick Laban and his friend Geremy 
-  Condra on the pyparsing wiki.
-  
-- Removed __slots__ declaration on ParseBaseException, for
-  compatibility with IronPython 2.0.1.  Raised by David
-  Lawler on the pyparsing wiki, thanks David!
-  
-- Fixed bug in SkipTo/failOn handling - caught by eagle eye 
-  cpennington on the pyparsing wiki!
-
-- Fixed second bug in SkipTo when using the ignore constructor
-  argument, reported by Catherine Devlin, thanks!
-  
-- Fixed obscure bug reported by Eike Welk when using a class
-  as a ParseAction with an errant __getitem__ method.
-
-- Simplified exception stack traces when reporting parse 
-  exceptions back to caller of parseString or parseFile - thanks
-  to a tip from Peter Otten on comp.lang.python.
-
-- Changed behavior of scanString to avoid infinitely looping on
-  expressions that match zero-length strings.  Prompted by a
-  question posted by ellisonbg on the wiki.
-
-- Enhanced classes that take a list of expressions (And, Or, 
-  MatchFirst, and Each) to accept generator expressions also.
-  This can be useful when generating lists of alternative
-  expressions, as in this case, where the user wanted to match
-  any repetitions of '+', '*', '#', or '.', but not mixtures
-  of them (that is, match '+++', but not '+-+'):
-  
-      codes = "+*#."
-      format = MatchFirst(Word(c) for c in codes)
-      
-  Based on a problem posed by Denis Spir on the Python tutor
-  list.
-
-- Added new example eval_arith.py, which extends the example
-  simpleArith.py to actually evaluate the parsed expressions.
-
-
-Version 1.5.1 - October, 2008
--------------------------------
-- Added new helper method originalTextFor, to replace the use of
-  the current keepOriginalText parse action.  Now instead of 
-  using the parse action, as in:
-  
-      fullName = Word(alphas) + Word(alphas)
-      fullName.setParseAction(keepOriginalText)
-      
-  (in this example, we used keepOriginalText to restore any white
-  space that may have been skipped between the first and last
-  names)
-  You can now write:
-  
-      fullName = originalTextFor(Word(alphas) + Word(alphas))
-      
-  The implementation of originalTextFor is simpler and faster than
-  keepOriginalText, and does not depend on using the inspect or
-  imp modules.
-  
-- Added optional parseAll argument to parseFile, to be consistent
-  with parseAll argument to parseString.  Posted by pboucher on the
-  pyparsing wiki, thanks!
-
-- Added failOn argument to SkipTo, so that grammars can define
-  literal strings or pyparsing expressions which, if found in the
-  skipped text, will cause SkipTo to fail.  Useful to prevent 
-  SkipTo from reading past terminating expression.  Instigated by
-  question posed by Aki Niimura on the pyparsing wiki.
-
-- Fixed bug in nestedExpr if multi-character expressions are given
-  for nesting delimiters.  Patch provided by new pyparsing user,
-  Hans-Martin Gaudecker - thanks, H-M!
-
-- Removed dependency on xml.sax.saxutils.escape, and included
-  internal implementation instead - proposed by Mike Droettboom on
-  the pyparsing mailing list, thanks Mike!  Also fixed erroneous
-  mapping in replaceHTMLEntity of &quot; to ', now correctly maps
-  to ".  (Also added support for mapping &apos; to '.)
-
-- Fixed typo in ParseResults.insert, found by Alejandro Dubrovsky,
-  good catch!
-
-- Added __dir__() methods to ParseBaseException and ParseResults,
-  to support new dir() behavior in Py2.6 and Py3.0.  If dir() is
-  called on a ParseResults object, the returned list will include
-  the base set of attribute names, plus any results names that are
-  defined.
-
-- Fixed bug in ParseResults.asXML(), in which the first named
-  item within a ParseResults gets reported with an <ITEM> tag 
-  instead of with the correct results name.
-  
-- Fixed bug in '-' error stop, when '-' operator is used inside a 
-  Combine expression.
-
-- Reverted generator expression to use list comprehension, for 
-  better compatibility with old versions of Python.  Reported by
-  jester/artixdesign on the SourceForge pyparsing discussion list.
-
-- Fixed bug in parseString(parseAll=True), when the input string
-  ends with a comment or whitespace.
-
-- Fixed bug in LineStart and LineEnd that did not recognize any
-  special whitespace chars defined using ParserElement.setDefault-
-  WhitespaceChars, found while debugging an issue for Marek Kubica,
-  thanks for the new test case, Marek!
-
-- Made Forward class more tolerant of subclassing.
-
-
-Version 1.5.0 - June, 2008
---------------------------
-This version of pyparsing includes work on two long-standing
-FAQ's: support for forcing parsing of the complete input string
-(without having to explicitly append StringEnd() to the grammar),
-and a method to improve the mechanism of detecting where syntax
-errors occur in an input string with various optional and
-alternative paths.  This release also includes a helper method
-to simplify definition of indentation-based grammars.  With
-these changes (and the past few minor updates), I thought it was
-finally time to bump the minor rev number on pyparsing - so
-1.5.0 is now available!  Read on...
-
-- AT LAST!!!  You can now call parseString and have it raise
-  an exception if the expression does not parse the entire
-  input string.  This has been an FAQ for a LONG time.
-
-  The parseString method now includes an optional parseAll
-  argument (default=False).  If parseAll is set to True, then
-  the given parse expression must parse the entire input
-  string.  (This is equivalent to adding StringEnd() to the
-  end of the expression.)  The default value is False to
-  retain backward compatibility.
-
-  Inspired by MANY requests over the years, most recently by
-  ecir-hana on the pyparsing wiki!
-
-- Added new operator '-' for composing grammar sequences. '-'
-  behaves just like '+' in creating And expressions, but '-'
-  is used to mark grammar structures that should stop parsing
-  immediately and report a syntax error, rather than just
-  backtracking to the last successful parse and trying another
-  alternative.  For instance, running the following code:
-
-    port_definition = Keyword("port") + '=' + Word(nums)
-    entity_definition = Keyword("entity") + "{" +
-        Optional(port_definition) + "}"
-
-    entity_definition.parseString("entity { port 100 }")
-
-  pyparsing fails to detect the missing '=' in the port definition.
-  But, since this expression is optional, pyparsing then proceeds
-  to try to match the closing '}' of the entity_definition.  Not
-  finding it, pyparsing reports that there was no '}' after the '{'
-  character.  Instead, we would like pyparsing to parse the 'port'
-  keyword, and if not followed by an equals sign and an integer,
-  to signal this as a syntax error.
-
-  This can now be done simply by changing the port_definition to:
-
-    port_definition = Keyword("port") - '=' + Word(nums)
-
-  Now after successfully parsing 'port', pyparsing must also find
-  an equals sign and an integer, or it will raise a fatal syntax
-  exception.
-
-  By judicious insertion of '-' operators, a pyparsing developer
-  can have their grammar report much more informative syntax error
-  messages.
-
-  Patches and suggestions proposed by several contributors on
-  the pyparsing mailing list and wiki - special thanks to
-  Eike Welk and Thomas/Poldy on the pyparsing wiki!
-
-- Added indentedBlock helper method, to encapsulate the parse
-  actions and indentation stack management needed to keep track of
-  indentation levels.  Use indentedBlock to define grammars for
-  indentation-based grouping grammars, like Python's.
-
-  indentedBlock takes up to 3 parameters:
-    - blockStatementExpr - expression defining syntax of statement
-        that is repeated within the indented block
-    - indentStack - list created by caller to manage indentation
-        stack (multiple indentedBlock expressions
-        within a single grammar should share a common indentStack)
-    - indent - boolean indicating whether block must be indented
-        beyond the the current level; set to False for block of
-        left-most statements (default=True)
-
-  A valid block must contain at least one indented statement.
-
-- Fixed bug in nestedExpr in which ignored expressions needed
-  to be set off with whitespace.  Reported by Stefaan Himpe,
-  nice catch!
-
-- Expanded multiplication of an expression by a tuple, to
-  accept tuple values of None:
-  . expr*(n,None) or expr*(n,) is equivalent
-    to expr*n + ZeroOrMore(expr)
-    (read as "at least n instances of expr")
-  . expr*(None,n) is equivalent to expr*(0,n)
-    (read as "0 to n instances of expr")
-  . expr*(None,None) is equivalent to ZeroOrMore(expr)
-  . expr*(1,None) is equivalent to OneOrMore(expr)
-
-  Note that expr*(None,n) does not raise an exception if
-  more than n exprs exist in the input stream; that is,
-  expr*(None,n) does not enforce a maximum number of expr
-  occurrences.  If this behavior is desired, then write
-  expr*(None,n) + ~expr
-
-- Added None as a possible operator for operatorPrecedence.
-  None signifies "no operator", as in multiplying m times x
-  in "y=mx+b".
-
-- Fixed bug in Each, reported by Michael Ramirez, in which the
-  order of terms in the Each affected the parsing of the results.
-  Problem was due to premature grouping of the expressions in
-  the overall Each during grammar construction, before the
-  complete Each was defined.  Thanks, Michael!
-
-- Also fixed bug in Each in which Optional's with default values
-  were not getting the defaults added to the results of the
-  overall Each expression.
-
-- Fixed a bug in Optional in which results names were not
-  assigned if a default value was supplied.
-
-- Cleaned up Py3K compatibility statements, including exception
-  construction statements, and better equivalence between _ustr
-  and basestring, and __nonzero__ and __bool__.
-
-
-Version 1.4.11 - February, 2008
--------------------------------
-- With help from Robert A. Clark, this version of pyparsing
-  is compatible with Python 3.0a3.  Thanks for the help,
-  Robert!
-
-- Added WordStart and WordEnd positional classes, to support
-  expressions that must occur at the start or end of a word.
-  Proposed by piranha on the pyparsing wiki, good idea!
-
-- Added matchOnlyAtCol helper parser action, to simplify
-  parsing log or data files that have optional fields that are
-  column dependent.  Inspired by a discussion thread with
-  hubritic on comp.lang.python.
-
-- Added withAttribute.ANY_VALUE as a match-all value when using
-  withAttribute.  Used to ensure that an attribute is present,
-  without having to match on the actual attribute value.
-
-- Added get() method to ParseResults, similar to dict.get().
-  Suggested by new pyparsing user, Alejandro Dubrovksy, thanks!
-
-- Added '==' short-cut to see if a given string matches a
-  pyparsing expression.  For instance, you can now write:
-
-    integer = Word(nums)
-    if "123" == integer:
-       # do something
-
-    print [ x for x in "123 234 asld".split() if x==integer ]
-    # prints ['123', '234']
-
-- Simplified the use of nestedExpr when using an expression for
-  the opening or closing delimiters.  Now the content expression
-  will not have to explicitly negate closing delimiters.  Found
-  while working with dfinnie on GHOP Task #277, thanks!
-
-- Fixed bug when defining ignorable expressions that are
-  later enclosed in a wrapper expression (such as ZeroOrMore,
-  OneOrMore, etc.) - found while working with Prabhu
-  Gurumurthy, thanks Prahbu!
-
-- Fixed bug in withAttribute in which keys were automatically
-  converted to lowercase, making it impossible to match XML
-  attributes with uppercase characters in them.  Using with-
-  Attribute requires that you reference attributes in all
-  lowercase if parsing HTML, and in correct case when parsing
-  XML.
-
-- Changed '<<' operator on Forward to return None, since this
-  is really used as a pseudo-assignment operator, not as a
-  left-shift operator.  By returning None, it is easier to
-  catch faulty statements such as a << b | c, where precedence
-  of operations causes the '|' operation to be performed
-  *after* inserting b into a, so no alternation is actually
-  implemented.  The correct form is a << (b | c).  With this
-  change, an error will be reported instead of silently
-  clipping the alternative term.  (Note: this may break some
-  existing code, but if it does, the code had a silent bug in
-  it anyway.)  Proposed by wcbarksdale on the pyparsing wiki,
-  thanks!
-
-- Several unit tests were added to pyparsing's regression
-  suite, courtesy of the Google Highly-Open Participation
-  Contest.  Thanks to all who administered and took part in
-  this event!
-
-
-Version 1.4.10 - December 9, 2007
----------------------------------
-- Fixed bug introduced in v1.4.8, parse actions were called for
-  intermediate operator levels, not just the deepest matching
-  operation level.  Again, big thanks to Torsten Marek for
-  helping isolate this problem!
-
-
-Version 1.4.9 - December 8, 2007
---------------------------------
-- Added '*' multiplication operator support when creating
-  grammars, accepting either an integer, or a two-integer
-  tuple multiplier, as in:
-    ipAddress = Word(nums) + ('.'+Word(nums))*3
-    usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
-  If multiplying by a tuple, the two integer values represent
-  min and max multiples.  Suggested by Vincent of eToy.com,
-  great idea, Vincent!
-
-- Fixed bug in nestedExpr, original version was overly greedy!
-  Thanks to Michael Ramirez for raising this issue.
-
-- Fixed internal bug in ParseResults - when an item was deleted,
-  the key indices were not updated.  Thanks to Tim Mitchell for
-  posting a bugfix patch to the SF bug tracking system!
-
-- Fixed internal bug in operatorPrecedence - when the results of
-  a right-associative term were sent to a parse action, the wrong
-  tokens were sent.  Reported by Torsten Marek, nice job!
-
-- Added pop() method to ParseResults.  If pop is called with an
-  integer or with no arguments, it will use list semantics and
-  update the ParseResults' list of tokens.  If pop is called with
-  a non-integer (a string, for instance), then it will use dict
-  semantics and update the ParseResults' internal dict.
-  Suggested by Donn Ingle, thanks Donn!
-
-- Fixed quoted string built-ins to accept '\xHH' hex characters
-  within the string.
-
-
-Version 1.4.8 - October, 2007
------------------------------
-- Added new helper method nestedExpr to easily create expressions
-  that parse lists of data in nested parentheses, braces, brackets,
-  etc.
-
-- Added withAttribute parse action helper, to simplify creating
-  filtering parse actions to attach to expressions returned by
-  makeHTMLTags and makeXMLTags.  Use withAttribute to qualify a
-  starting tag with one or more required attribute values, to avoid
-  false matches on common tags such as <TD> or <DIV>.
-
-- Added new examples nested.py and withAttribute.py to demonstrate
-  the new features.
-
-- Added performance speedup to grammars using operatorPrecedence,
-  instigated by Stefan Reich�r - thanks for the feedback, Stefan!
-
-- Fixed bug/typo when deleting an element from a ParseResults by
-  using the element's results name.
-
-- Fixed whitespace-skipping bug in wrapper classes (such as Group,
-  Suppress, Combine, etc.) and when using setDebug(), reported by
-  new pyparsing user dazzawazza on SourceForge, nice job!
-
-- Added restriction to prevent defining Word or CharsNotIn expressions
-  with minimum length of 0 (should use Optional if this is desired),
-  and enhanced docstrings to reflect this limitation.  Issue was
-  raised by Joey Tallieu, who submitted a patch with a slightly
-  different solution.  Thanks for taking the initiative, Joey, and
-  please keep submitting your ideas!
-
-- Fixed bug in makeHTMLTags that did not detect HTML tag attributes
-  with no '= value' portion (such as "<td nowrap>"), reported by
-  hamidh on the pyparsing wiki - thanks!
-
-- Fixed minor bug in makeHTMLTags and makeXMLTags, which did not
-  accept whitespace in closing tags.
-
-
-Version 1.4.7 - July, 2007
---------------------------
-- NEW NOTATION SHORTCUT: ParserElement now accepts results names using
-  a notational shortcut, following the expression with the results name
-  in parentheses.  So this:
-
-    stats = "AVE:" + realNum.setResultsName("average") + \
-            "MIN:" + realNum.setResultsName("min") + \
-            "MAX:" + realNum.setResultsName("max")
-
-  can now be written as this:
-
-    stats = "AVE:" + realNum("average") + \
-            "MIN:" + realNum("min") + \
-            "MAX:" + realNum("max")
-
-  The intent behind this change is to make it simpler to define results
-  names for significant fields within the expression, while keeping
-  the grammar syntax clean and uncluttered.
-
-- Fixed bug when packrat parsing is enabled, with cached ParseResults
-  being updated by subsequent parsing.  Reported on the pyparsing
-  wiki by Kambiz, thanks!
-
-- Fixed bug in operatorPrecedence for unary operators with left
-  associativity, if multiple operators were given for the same term.
-
-- Fixed bug in example simpleBool.py, corrected precedence of "and" vs.
-  "or" operations.
-
-- Fixed bug in Dict class, in which keys were converted to strings
-  whether they needed to be or not.  Have narrowed this logic to
-  convert keys to strings only if the keys are ints (which would
-  confuse __getitem__ behavior for list indexing vs. key lookup).
-
-- Added ParserElement method setBreak(), which will invoke the pdb
-  module's set_trace() function when this expression is about to be
-  parsed.
-
-- Fixed bug in StringEnd in which reading off the end of the input
-  string raises an exception - should match.  Resolved while
-  answering a question for Shawn on the pyparsing wiki.
-
-
-Version 1.4.6 - April, 2007
----------------------------
-- Simplified constructor for ParseFatalException, to support common
-  exception construction idiom:
-    raise ParseFatalException, "unexpected text: 'Spanish Inquisition'"
-
-- Added method getTokensEndLoc(), to be called from within a parse action,
-  for those parse actions that need both the starting *and* ending
-  location of the parsed tokens within the input text.
-
-- Enhanced behavior of keepOriginalText so that named parse fields are
-  preserved, even though tokens are replaced with the original input
-  text matched by the current expression.  Also, cleaned up the stack
-  traversal to be more robust.  Suggested by Tim Arnold - thanks, Tim!
-
-- Fixed subtle bug in which countedArray (and similar dynamic
-  expressions configured in parse actions) failed to match within Or,
-  Each, FollowedBy, or NotAny.  Reported by Ralf Vosseler, thanks for
-  your patience, Ralf!
-
-- Fixed Unicode bug in upcaseTokens and downcaseTokens parse actions,
-  scanString, and default debugging actions; reported (and patch submitted)
-  by Nikolai Zamkovoi, spasibo!
-
-- Fixed bug when saving a tuple as a named result.  The returned
-  token list gave the proper tuple value, but accessing the result by
-  name only gave the first element of the tuple.  Reported by
-  Poromenos, nice catch!
-
-- Fixed bug in makeHTMLTags/makeXMLTags, which failed to match tag
-  attributes with namespaces.
-
-- Fixed bug in SkipTo when setting include=True, to have the skipped-to
-  tokens correctly included in the returned data.  Reported by gunars on
-  the pyparsing wiki, thanks!
-
-- Fixed typobug in OnceOnly.reset method, omitted self argument.
-  Submitted by eike welk, thanks for the lint-picking!
-
-- Added performance enhancement to Forward class, suggested by
-  akkartik on the pyparsing Wiki discussion, nice work!
-
-- Added optional asKeyword to Word constructor, to indicate that the
-  given word pattern should be matched only as a keyword, that is, it
-  should only match if it is within word boundaries.
-
-- Added S-expression parser to examples directory.
-
-- Added macro substitution example to examples directory.
-
-- Added holaMundo.py example, excerpted from Marco Alfonso's blog -
-  muchas gracias, Marco!
-
-- Modified internal cyclic references in ParseResults to use weakrefs;
-  this should help reduce the memory footprint of large parsing
-  programs, at some cost to performance (3-5%). Suggested by bca48150 on
-  the pyparsing wiki, thanks!
-
-- Enhanced the documentation describing the vagaries and idiosyncracies
-  of parsing strings with embedded tabs, and the impact on:
-  . parse actions
-  . scanString
-  . col and line helper functions
-  (Suggested by eike welk in response to some unexplained inconsistencies
-  between parsed location and offsets in the input string.)
-
-- Cleaned up internal decorators to preserve function names,
-  docstrings, etc.
-
-
-Version 1.4.5 - December, 2006
-------------------------------
-- Removed debugging print statement from QuotedString class.  Sorry
-  for not stripping this out before the 1.4.4 release!
-
-- A significant performance improvement, the first one in a while!
-  For my Verilog parser, this version of pyparsing is about double the
-  speed - YMMV.
-
-- Added support for pickling of ParseResults objects.  (Reported by
-  Jeff Poole, thanks Jeff!)
-
-- Fixed minor bug in makeHTMLTags that did not recognize tag attributes
-  with embedded '-' or '_' characters.  Also, added support for
-  passing expressions to makeHTMLTags and makeXMLTags, and used this
-  feature to define the globals anyOpenTag and anyCloseTag.
-
-- Fixed error in alphas8bit, I had omitted the y-with-umlaut character.
-
-- Added punc8bit string to complement alphas8bit - it contains all the
-  non-alphabetic, non-blank 8-bit characters.
-
-- Added commonHTMLEntity expression, to match common HTML "ampersand"
-  codes, such as "&lt;", "&gt;", "&amp;", "&nbsp;", and "&quot;".  This
-  expression also defines a results name 'entity', which can be used
-  to extract the entity field (that is, "lt", "gt", etc.).  Also added
-  built-in parse action replaceHTMLEntity, which can be attached to
-  commonHTMLEntity to translate "&lt;", "&gt;", "&amp;", "&nbsp;", and
-  "&quot;" to "<", ">", "&", " ", and "'".
-
-- Added example, htmlStripper.py, that strips HTML tags and scripts
-  from HTML pages.  It also translates common HTML entities to their
-  respective characters.
-
-
-Version 1.4.4 - October, 2006
--------------------------------
-- Fixed traceParseAction decorator to also trap and record exception
-  returns from parse actions, and to handle parse actions with 0,
-  1, 2, or 3 arguments.
-
-- Enhanced parse action normalization to support using classes as
-  parse actions; that is, the class constructor is called at parse
-  time and the __init__ function is called with 0, 1, 2, or 3
-  arguments.  If passing a class as a parse action, the __init__
-  method must use one  of the valid parse action parameter list
-  formats. (This technique is useful when using pyparsing to compile
-  parsed text into a series of application objects - see the new
-  example simpleBool.py.)
-
-- Fixed bug in ParseResults when setting an item using an integer
-  index. (Reported by Christopher Lambacher, thanks!)
-
-- Fixed whitespace-skipping bug, patch submitted by Paolo Losi -
-  grazie, Paolo!
-
-- Fixed bug when a Combine contained an embedded Forward expression,
-  reported by cie on the pyparsing wiki - good catch!
-
-- Fixed listAllMatches bug, when a listAllMatches result was
-  nested within another result. (Reported by don pasquale on
-  comp.lang.python, well done!)
-
-- Fixed bug in ParseResults items() method, when returning an item
-  marked as listAllMatches=True
-
-- Fixed bug in definition of cppStyleComment (and javaStyleComment)
-  in which '//' line comments were not continued to the next line
-  if the line ends with a '\'.  (Reported by eagle-eyed Ralph
-  Corderoy!)
-
-- Optimized re's for cppStyleComment and quotedString for better
-  re performance - also provided by Ralph Corderoy, thanks!
-
-- Added new example, indentedGrammarExample.py, showing how to
-  define a grammar using indentation to show grouping (as Python
-  does for defining statement nesting).  Instigated by an e-mail
-  discussion with Andrew Dalke, thanks Andrew!
-
-- Added new helper operatorPrecedence (based on e-mail list discussion
-  with Ralph Corderoy and Paolo Losi), to facilitate definition of
-  grammars for expressions with unary and binary operators.  For
-  instance, this grammar defines a 6-function arithmetic expression
-  grammar, with unary plus and minus, proper operator precedence,and
-  right- and left-associativity:
-
-    expr = operatorPrecedence( operand,
-        [("!", 1, opAssoc.LEFT),
-         ("^", 2, opAssoc.RIGHT),
-         (oneOf("+ -"), 1, opAssoc.RIGHT),
-         (oneOf("* /"), 2, opAssoc.LEFT),
-         (oneOf("+ -"), 2, opAssoc.LEFT),]
-        )
-
-  Also added example simpleArith.py and simpleBool.py to provide
-  more detailed code samples using this new helper method.
-
-- Added new helpers matchPreviousLiteral and matchPreviousExpr, for
-  creating adaptive parsing expressions that match the same content
-  as was parsed in a previous parse expression.  For instance:
-
-        first = Word(nums)
-        matchExpr = first + ":" + matchPreviousLiteral(first)
-
-  will match "1:1", but not "1:2".  Since this matches at the literal
-  level, this will also match the leading "1:1" in "1:10".
-
-  In contrast:
-
-        first = Word(nums)
-        matchExpr = first + ":" + matchPreviousExpr(first)
-
-  will *not* match the leading "1:1" in "1:10"; the expressions are
-  evaluated first, and then compared, so "1" is compared with "10".
-
-- Added keepOriginalText parse action.  Sometimes pyparsing's
-  whitespace-skipping leaves out too much whitespace.  Adding this
-  parse action will restore any internal whitespace for a parse
-  expression.  This is especially useful when defining expressions
-  for scanString or transformString applications.
-
-- Added __add__ method for ParseResults class, to better support
-  using Python sum built-in for summing ParseResults objects returned
-  from scanString.
-
-- Added reset method for the new OnlyOnce class wrapper for parse
-  actions (to allow a grammar to be used multiple times).
-
-- Added optional maxMatches argument to scanString and searchString,
-  to short-circuit scanning after 'n' expression matches are found.
-
-
-Version 1.4.3 - July, 2006
-------------------------------
-- Fixed implementation of multiple parse actions for an expression
-  (added in 1.4.2).
-  . setParseAction() reverts to its previous behavior, setting
-    one (or more) actions for an expression, overwriting any
-    action or actions previously defined
-  . new method addParseAction() appends one or more parse actions
-    to the list of parse actions attached to an expression
-  Now it is harder to accidentally append parse actions to an
-  expression, when what you wanted to do was overwrite whatever had
-  been defined before.  (Thanks, Jean-Paul Calderone!)
-
-- Simplified interface to parse actions that do not require all 3
-  parse action arguments.  Very rarely do parse actions require more
-  than just the parsed tokens, yet parse actions still require all
-  3 arguments including the string being parsed and the location
-  within the string where the parse expression was matched.  With this
-  release, parse actions may now be defined to be called as:
-  . fn(string,locn,tokens)  (the current form)
-  . fn(locn,tokens)
-  . fn(tokens)
-  . fn()
-  The setParseAction and addParseAction methods will internally decorate
-  the provided parse actions with compatible wrappers to conform to
-  the full (string,locn,tokens) argument sequence.
-
-- REMOVED SUPPORT FOR RETURNING PARSE LOCATION FROM A PARSE ACTION.
-  I announced this in March, 2004, and gave a final warning in the last
-  release.  Now you can return a tuple from a parse action, and it will
-  be treated like any other return value (i.e., the tuple will be
-  substituted for the incoming tokens passed to the parse action,
-  which is useful when trying to parse strings into tuples).
-
-- Added setFailAction method, taking a callable function fn that
-  takes the arguments fn(s,loc,expr,err) where:
-  . s - string being parsed
-  . loc - location where expression match was attempted and failed
-  . expr - the parse expression that failed
-  . err - the exception thrown
-  The function returns no values.  It may throw ParseFatalException
-  if it is desired to stop parsing immediately.
-  (Suggested by peter21081944 on wikispaces.com)
-
-- Added class OnlyOnce as helper wrapper for parse actions.  OnlyOnce
-  only permits a parse action to be called one time, after which
-  all subsequent calls throw a ParseException.
-
-- Added traceParseAction decorator to help debug parse actions.
-  Simply insert "@traceParseAction" ahead of the definition of your
-  parse action, and each invocation will be displayed, along with
-  incoming arguments, and returned value.
-
-- Fixed bug when copying ParserElements using copy() or
-  setResultsName().  (Reported by Dan Thill, great catch!)
-
-- Fixed bug in asXML() where token text contains <, >, and &
-  characters - generated XML now escapes these as &lt;, &gt; and
-  &amp;.  (Reported by Jacek Sieka, thanks!)
-
-- Fixed bug in SkipTo() when searching for a StringEnd(). (Reported
-  by Pete McEvoy, thanks Pete!)
-
-- Fixed "except Exception" statements, the most critical added as part
-  of the packrat parsing enhancement.  (Thanks, Erick Tryzelaar!)
-
-- Fixed end-of-string infinite looping on LineEnd and StringEnd
-  expressions.  (Thanks again to Erick Tryzelaar.)
-
-- Modified setWhitespaceChars to return self, to be consistent with
-  other ParserElement modifiers. (Suggested by Erick Tryzelaar.)
-
-- Fixed bug/typo in new ParseResults.dump() method.
-
-- Fixed bug in searchString() method, in which only the first token of
-  an expression was returned.  searchString() now returns a
-  ParseResults collection of all search matches.
-
-- Added example program removeLineBreaks.py, a string transformer that
-  converts text files with hard line-breaks into one with line breaks
-  only between paragraphs.
-
-- Added example program listAllMatches.py, to illustrate using the
-  listAllMatches option when specifying results names (also shows new
-  support for passing lists to oneOf).
-
-- Added example program linenoExample.py, to illustrate using the
-  helper methods lineno, line, and col, and returning objects from a
-  parse action.
-
-- Added example program parseListString.py, to which can parse the
-  string representation of a Python list back into a true list.  Taken
-  mostly from my PyCon presentation examples, but now with support
-  for tuple elements, too!
-
-
-
-Version 1.4.2 - April 1, 2006 (No foolin'!)
--------------------------------------------
-- Significant speedup from memoizing nested expressions (a technique
-  known as "packrat parsing"), thanks to Chris Lesniewski-Laas!  Your
-  mileage may vary, but my Verilog parser almost doubled in speed to
-  over 600 lines/sec!
-
-  This speedup may break existing programs that use parse actions that
-  have side-effects.  For this reason, packrat parsing is disabled when
-  you first import pyparsing.  To activate the packrat feature, your
-  program must call the class method ParserElement.enablePackrat().  If
-  your program uses psyco to "compile as you go", you must call
-  enablePackrat before calling psyco.full().  If you do not do this,
-  Python will crash.  For best results, call enablePackrat() immediately
-  after importing pyparsing.
-
-- Added new helper method countedArray(expr), for defining patterns that
-  start with a leading integer to indicate the number of array elements,
-  followed by that many elements, matching the given expr parse
-  expression.  For instance, this two-liner:
-    wordArray = countedArray(Word(alphas))
-    print wordArray.parseString("3 Practicality beats purity")[0]
-  returns the parsed array of words:
-    ['Practicality', 'beats', 'purity']
-  The leading token '3' is suppressed, although it is easily obtained
-  from the length of the returned array.
-  (Inspired by e-mail discussion with Ralf Vosseler.)
-
-- Added support for attaching multiple parse actions to a single
-  ParserElement. (Suggested by Dan "Dang" Griffith - nice idea, Dan!)
-
-- Added support for asymmetric quoting characters in the recently-added
-  QuotedString class.  Now you can define your own quoted string syntax
-  like "<<This is a string in double angle brackets.>>".  To define
-  this custom form of QuotedString, your code would define:
-    dblAngleQuotedString = QuotedString('<<',endQuoteChar='>>')
-  QuotedString also supports escaped quotes, escape character other
-  than '\', and multiline.
-
-- Changed the default value returned internally by Optional, so that
-  None can be used as a default value.  (Suggested by Steven Bethard -
-  I finally saw the light!)
-
-- Added dump() method to ParseResults, to make it easier to list out
-  and diagnose values returned from calling parseString.
-
-- A new example, a search query string parser, submitted by Steven
-  Mooij and Rudolph Froger - a very interesting application, thanks!
-
-- Added an example that parses the BNF in Python's Grammar file, in
-  support of generating Python grammar documentation. (Suggested by
-  J H Stovall.)
-
-- A new example, submitted by Tim Cera, of a flexible parser module,
-  using a simple config variable to adjust parsing for input formats
-  that have slight variations - thanks, Tim!
-
-- Added an example for parsing Roman numerals, showing the capability
-  of parse actions to "compile" Roman numerals into their integer
-  values during parsing.
-
-- Added a new docs directory, for additional documentation or help.
-  Currently, this includes the text and examples from my recent
-  presentation at PyCon.
-
-- Fixed another typo in CaselessKeyword, thanks Stefan Behnel.
-
-- Expanded oneOf to also accept tuples, not just lists.  This really
-  should be sufficient...
-
-- Added deprecation warnings when tuple is returned from a parse action.
-  Looking back, I see that I originally deprecated this feature in March,
-  2004, so I'm guessing people really shouldn't have been using this
-  feature - I'll drop it altogether in the next release, which will
-  allow users to return a tuple from a parse action (which is really
-  handy when trying to reconstuct tuples from a tuple string
-  representation!).
-
-
-Version 1.4.1 - February, 2006
-------------------------------
-- Converted generator expression in QuotedString class to list
-  comprehension, to retain compatibility with Python 2.3. (Thanks, Titus
-  Brown for the heads-up!)
-
-- Added searchString() method to ParserElement, as an alternative to
-  using "scanString(instring).next()[0][0]" to search through a string
-  looking for a substring matching a given parse expression. (Inspired by
-  e-mail conversation with Dave Feustel.)
-
-- Modified oneOf to accept lists of strings as well as a single string
-  of space-delimited literals.  (Suggested by Jacek Sieka - thanks!)
-
-- Removed deprecated use of Upcase in pyparsing test code. (Also caught by
-  Titus Brown.)
-
-- Removed lstrip() call from Literal - too aggressive in stripping
-  whitespace which may be valid for some grammars.  (Point raised by Jacek
-  Sieka).  Also, made Literal more robust in the event of passing an empty
-  string.
-
-- Fixed bug in replaceWith when returning None.
-
-- Added cautionary documentation for Forward class when assigning a
-  MatchFirst expression, as in:
-    fwdExpr << a | b | c
-  Precedence of operators causes this to be evaluated as:
-    (fwdExpr << a) | b | c
-  thereby leaving b and c out as parseable alternatives.  Users must
-  explicitly group the values inserted into the Forward:
-    fwdExpr << (a | b | c)
-  (Suggested by Scot Wilcoxon - thanks, Scot!)
-
-
-Version 1.4 - January 18, 2006
-------------------------------
-- Added Regex class, to permit definition of complex embedded expressions
-  using regular expressions. (Enhancement provided by John Beisley, great
-  job!)
-
-- Converted implementations of Word, oneOf, quoted string, and comment
-  helpers to utilize regular expression matching.  Performance improvements
-  in the 20-40% range.
-
-- Added QuotedString class, to support definition of non-standard quoted
-  strings (Suggested by Guillaume Proulx, thanks!)
-
-- Added CaselessKeyword class, to streamline grammars with, well, caseless
-  keywords (Proposed by Stefan Behnel, thanks!)
-
-- Fixed bug in SkipTo, when using an ignoreable expression. (Patch provided
-  by Anonymous, thanks, whoever-you-are!)
-
-- Fixed typo in NoMatch class. (Good catch, Stefan Behnel!)
-
-- Fixed minor bug in _makeTags(), using string.printables instead of
-  pyparsing.printables.
-
-- Cleaned up some of the expressions created by makeXXXTags helpers, to
-  suppress extraneous <> characters.
-
-- Added some grammar definition-time checking to verify that a grammar is
-  being built using proper ParserElements.
-
-- Added examples:
-  . LAparser.py - linear algebra C preprocessor (submitted by Mike Ellis,
-    thanks Mike!)
-  . wordsToNum.py - converts word description of a number back to
-    the original number (such as 'one hundred and twenty three' -> 123)
-  . updated fourFn.py to support unary minus, added BNF comments
-
-
-Version 1.3.3 - September 12, 2005
-----------------------------------
-- Improved support for Unicode strings that would be returned using
-  srange.  Added greetingInKorean.py example, for a Korean version of
-  "Hello, World!" using Unicode. (Thanks, June Kim!)
-
-- Added 'hexnums' string constant (nums+"ABCDEFabcdef") for defining
-  hexadecimal value expressions.
-
-- NOTE: ===THIS CHANGE MAY BREAK EXISTING CODE===
-  Modified tag and results definitions returned by makeHTMLTags(),
-  to better support the looseness of HTML parsing.  Tags to be
-  parsed are now caseless, and keys generated for tag attributes are
-  now converted to lower case.
-
-  Formerly, makeXMLTags("XYZ") would return a tag with results
-  name of "startXYZ", this has been changed to "startXyz".  If this
-  tag is matched against '<XYZ Abc="1" DEF="2" ghi="3">', the
-  matched keys formerly would be "Abc", "DEF", and "ghi"; keys are
-  now converted to lower case, giving keys of "abc", "def", and
-  "ghi".  These changes were made to try to address the lax
-  case sensitivity agreement between start and end tags in many
-  HTML pages.
-
-  No changes were made to makeXMLTags(), which assumes more rigorous
-  parsing rules.
-
-  Also, cleaned up case-sensitivity bugs in closing tags, and
-  switched to using Keyword instead of Literal class for tags.
-  (Thanks, Steve Young, for getting me to look at these in more
-  detail!)
-
-- Added two helper parse actions, upcaseTokens and downcaseTokens,
-  which will convert matched text to all uppercase or lowercase,
-  respectively.
-
-- Deprecated Upcase class, to be replaced by upcaseTokens parse
-  action.
-
-- Converted messages sent to stderr to use warnings module, such as
-  when constructing a Literal with an empty string, one should use
-  the Empty() class or the empty helper instead.
-
-- Added ' ' (space) as an escapable character within a quoted
-  string.
-
-- Added helper expressions for common comment types, in addition
-  to the existing cStyleComment (/*...*/) and htmlStyleComment
-  (<!-- ... -->)
-  . dblSlashComment = // ... (to end of line)
-  . cppStyleComment = cStyleComment or dblSlashComment
-  . javaStyleComment = cppStyleComment
-  . pythonStyleComment = # ... (to end of line)
-
-
-
-Version 1.3.2 - July 24, 2005
------------------------------
-- Added Each class as an enhanced version of And.  'Each' requires
-  that all given expressions be present, but may occur in any order.
-  Special handling is provided to group ZeroOrMore and OneOrMore
-  elements that occur out-of-order in the input string.  You can also
-  construct 'Each' objects by joining expressions with the '&'
-  operator.  When using the Each class, results names are strongly
-  recommended for accessing the matched tokens. (Suggested by Pradam
-  Amini - thanks, Pradam!)
-
-- Stricter interpretation of 'max' qualifier on Word elements.  If the
-  'max' attribute is specified, matching will fail if an input field
-  contains more than 'max' consecutive body characters.  For example,
-  previously, Word(nums,max=3) would match the first three characters
-  of '0123456', returning '012' and continuing parsing at '3'.  Now,
-  when constructed using the max attribute, Word will raise an
-  exception with this string.
-
-- Cleaner handling of nested dictionaries returned by Dict.  No
-  longer necessary to dereference sub-dictionaries as element [0] of
-  their parents.
-  === NOTE: THIS CHANGE MAY BREAK SOME EXISTING CODE, BUT ONLY IF
-  PARSING NESTED DICTIONARIES USING THE LITTLE-USED DICT CLASS ===
-  (Prompted by discussion thread on the Python Tutor list, with
-  contributions from Danny Yoo, Kent Johnson, and original post by
-  Liam Clarke - thanks all!)
-
-
-
-Version 1.3.1 - June, 2005
-----------------------------------
-- Added markInputline() method to ParseException, to display the input
-  text line location of the parsing exception. (Thanks, Stefan Behnel!)
-
-- Added setDefaultKeywordChars(), so that Keyword definitions using a
-  custom keyword character set do not all need to add the keywordChars
-  constructor argument (similar to setDefaultWhitespaceChars()).
-  (suggested by rzhanka on the SourceForge pyparsing forum.)
-
-- Simplified passing debug actions to setDebugAction().  You can now
-  pass 'None' for a debug action if you want to take the default
-  debug behavior.  To suppress a particular debug action, you can pass
-  the pyparsing method nullDebugAction.
-
-- Refactored parse exception classes, moved all behavior to
-  ParseBaseException, and the former ParseException is now a subclass of
-  ParseBaseException.  Added a second subclass, ParseFatalException, as
-  a subclass of ParseBaseException.  User-defined parse actions can raise
-  ParseFatalException if a data inconsistency is detected (such as a
-  begin-tag/end-tag mismatch), and this will stop all parsing immediately.
-  (Inspired by e-mail thread with Michele Petrazzo - thanks, Michelle!)
-
-- Added helper methods makeXMLTags and makeHTMLTags, that simplify the
-  definition of XML or HTML tag parse expressions for a given tagname.
-  Both functions return a pair of parse expressions, one for the opening
-  tag (that is, '<tagname>') and one for the closing tag ('</tagname>').
-  The opening tagame also recognizes any attribute definitions that have
-  been included in the opening tag, as well as an empty tag (one with a
-  trailing '/', as in '<BODY/>' which is equivalent to '<BODY></BODY>').
-  makeXMLTags uses stricter XML syntax for attributes, requiring that they
-  be enclosed in double quote characters - makeHTMLTags is more lenient,
-  and accepts single-quoted strings or any contiguous string of characters
-  up to the next whitespace character or '>' character.  Attributes can
-  be retrieved as dictionary or attribute values of the returned results
-  from the opening tag.
-
-- Added example minimath2.py, a refinement on fourFn.py that adds
-  an interactive session and support for variables.  (Thanks, Steven Siew!)
-
-- Added performance improvement, up to 20% reduction!  (Found while working
-  with Wolfgang Borgert on performance tuning of his TTCN3 parser.)
-
-- And another performance improvement, up to 25%, when using scanString!
-  (Found while working with Henrik Westlund on his C header file scanner.)
-
-- Updated UML diagrams to reflect latest class/method changes.
-
-
-Version 1.3 - March, 2005
-----------------------------------
-- Added new Keyword class, as a special form of Literal.  Keywords
-  must be followed by whitespace or other non-keyword characters, to
-  distinguish them from variables or other identifiers that just
-  happen to start with the same characters as a keyword.  For instance,
-  the input string containing "ifOnlyIfOnly" will match a Literal("if")
-  at the beginning and in the middle, but will fail to match a
-  Keyword("if").  Keyword("if") will match only strings such as "if only"
-  or "if(only)". (Proposed by Wolfgang Borgert, and Berteun Damman
-  separately requested this on comp.lang.python - great idea!)
-
-- Added setWhitespaceChars() method to override the characters to be
-  skipped as whitespace before matching a particular ParseElement.  Also
-  added the class-level method setDefaultWhitespaceChars(), to allow
-  users to override the default set of whitespace characters (space,
-  tab, newline, and return) for all subsequently defined ParseElements.
-  (Inspired by Klaas Hofstra's inquiry on the Sourceforge pyparsing
-  forum.)
-
-- Added helper parse actions to support some very common parse
-  action use cases:
-  . replaceWith(replStr) - replaces the matching tokens with the
-    provided replStr replacement string; especially useful with
-    transformString()
-  . removeQuotes - removes first and last character from string enclosed
-    in quotes (note - NOT the same as the string strip() method, as only
-    a single character is removed at each end)
-
-- Added copy() method to ParseElement, to make it easier to define
-  different parse actions for the same basic parse expression.  (Note, copy
-  is implicitly called when using setResultsName().)
-
-
-  (The following changes were posted to CVS as Version 1.2.3 -
-  October-December, 2004)
-
-- Added support for Unicode strings in creating grammar definitions.
-  (Big thanks to Gavin Panella!)
-
-- Added constant alphas8bit to include the following 8-bit characters:
-    �������������������������������������������������������������
-
-- Added srange() function to simplify definition of Word elements, using
-  regexp-like '[A-Za-z0-9]' syntax.  This also simplifies referencing
-  common 8-bit characters.
-
-- Fixed bug in Dict when a single element Dict was embedded within another
-  Dict. (Thanks Andy Yates for catching this one!)
-
-- Added 'formatted' argument to ParseResults.asXML().  If set to False,
-  suppresses insertion of whitespace for pretty-print formatting.  Default
-  equals True for backward compatibility.
-
-- Added setDebugActions() function to ParserElement, to allow user-defined
-  debugging actions.
-
-- Added support for escaped quotes (either in \', \", or doubled quote
-  form) to the predefined expressions for quoted strings. (Thanks, Ero
-  Carrera!)
-
-- Minor performance improvement (~5%) converting "char in string" tests
-  to "char in dict". (Suggested by Gavin Panella, cool idea!)
-
-
-Version 1.2.2 - September 27, 2004
-----------------------------------
-- Modified delimitedList to accept an expression as the delimiter, instead
-  of only accepting strings.
-
-- Modified ParseResults, to convert integer field keys to strings (to
-  avoid confusion with list access).
-
-- Modified Combine, to convert all embedded tokens to strings before
-  combining.
-
-- Fixed bug in MatchFirst in which parse actions would be called for
-  expressions that only partially match. (Thanks, John Hunter!)
-
-- Fixed bug in fourFn.py example that fixes right-associativity of ^
-  operator. (Thanks, Andrea Griffini!)
-
-- Added class FollowedBy(expression), to look ahead in the input string
-  without consuming tokens.
-
-- Added class NoMatch that never matches any input. Can be useful in
-  debugging, and in very specialized grammars.
-
-- Added example pgn.py, for parsing chess game files stored in Portable
-  Game Notation. (Thanks, Alberto Santini!)
-
-
-Version 1.2.1 - August 19, 2004
--------------------------------
-- Added SkipTo(expression) token type, simplifying grammars that only
-  want to specify delimiting expressions, and want to match any characters
-  between them.
-
-- Added helper method dictOf(key,value), making it easier to work with
-  the Dict class. (Inspired by Pavel Volkovitskiy, thanks!).
-
-- Added optional argument listAllMatches (default=False) to
-  setResultsName().  Setting listAllMatches to True overrides the default
-  modal setting of tokens to results names; instead, the results name
-  acts as an accumulator for all matching tokens within the local
-  repetition group. (Suggested by Amaury Le Leyzour - thanks!)
-
-- Fixed bug in ParseResults, throwing exception when trying to extract
-  slice, or make a copy using [:]. (Thanks, Wilson Fowlie!)
-
-- Fixed bug in transformString() when the input string contains <TAB>'s
-  (Thanks, Rick Walia!).
-
-- Fixed bug in returning tokens from un-Grouped And's, Or's and
-  MatchFirst's, where too many tokens would be included in the results,
-  confounding parse actions and returned results.
-
-- Fixed bug in naming ParseResults returned by And's, Or's, and Match
-  First's.
-
-- Fixed bug in LineEnd() - matching this token now correctly consumes
-  and returns the end of line "\n".
-
-- Added a beautiful example for parsing Mozilla calendar files (Thanks,
-  Petri Savolainen!).
-
-- Added support for dynamically modifying Forward expressions during
-  parsing.
-
-
-Version 1.2 - 20 June 2004
---------------------------
-- Added definition for htmlComment to help support HTML scanning and
-  parsing.
-
-- Fixed bug in generating XML for Dict classes, in which trailing item was
-  duplicated in the output XML.
-
-- Fixed release bug in which scanExamples.py was omitted from release
-  files.
-
-- Fixed bug in transformString() when parse actions are not defined on the
-  outermost parser element.
-
-- Added example urlExtractor.py, as another example of using scanString
-  and parse actions.
-
-
-Version 1.2beta3 - 4 June 2004
-------------------------------
-- Added White() token type, analogous to Word, to match on whitespace
-  characters.  Use White in parsers with significant whitespace (such as
-  configuration file parsers that use indentation to indicate grouping).
-  Construct White with a string containing the whitespace characters to be
-  matched.  Similar to Word, White also takes optional min, max, and exact
-  parameters.
-
-- As part of supporting whitespace-signficant parsing, added parseWithTabs()
-  method to ParserElement, to override the default behavior in parseString
-  of automatically expanding tabs to spaces.  To retain tabs during
-  parsing, call parseWithTabs() before calling parseString(), parseFile() or
-  scanString(). (Thanks, Jean-Guillaume Paradis for catching this, and for
-  your suggestions on whitespace-significant parsing.)
-
-- Added transformString() method to ParseElement, as a complement to
-  scanString().  To use transformString, define a grammar and attach a parse
-  action to the overall grammar that modifies the returned token list.
-  Invoking transformString() on a target string will then scan for matches,
-  and replace the matched text patterns according to the logic in the parse
-  action.  transformString() returns the resulting transformed string.
-  (Note: transformString() does *not* automatically expand tabs to spaces.)
-  Also added scanExamples.py to the examples directory to show sample uses of
-  scanString() and transformString().
-
-- Removed group() method that was introduced in beta2.  This turns out NOT to
-  be equivalent to nesting within a Group() object, and I'd prefer not to sow
-  more seeds of confusion.
-
-- Fixed behavior of asXML() where tags for groups were incorrectly duplicated.
-  (Thanks, Brad Clements!)
-
-- Changed beta version message to display to stderr instead of stdout, to
-  make asXML() easier to use.  (Thanks again, Brad.)
-
-
-Version 1.2beta2 - 19 May 2004
-------------------------------
-- *** SIMPLIFIED API *** - Parse actions that do not modify the list of tokens
-  no longer need to return a value.  This simplifies those parse actions that
-  use the list of tokens to update a counter or record or display some of the
-  token content; these parse actions can simply end without having to specify
-  'return toks'.
-
-- *** POSSIBLE API INCOMPATIBILITY *** - Fixed CaselessLiteral bug, where the
-  returned token text was not the original string (as stated in the docs),
-  but the original string converted to upper case.  (Thanks, Dang Griffith!)
-  **NOTE: this may break some code that relied on this erroneous behavior.
-  Users should scan their code for uses of CaselessLiteral.**
-
-- *** POSSIBLE CODE INCOMPATIBILITY *** - I have renamed the internal
-  attributes on ParseResults from 'dict' and 'list' to '__tokdict' and
-  '__toklist', to avoid collisions with user-defined data fields named 'dict'
-  and 'list'.  Any client code that accesses these attributes directly will
-  need to be modified.  Hopefully the implementation of methods such as keys(),
-  items(), len(), etc. on ParseResults will make such direct attribute
-  accessess unnecessary.
-
-- Added asXML() method to ParseResults.  This greatly simplifies the process
-  of parsing an input data file and generating XML-structured data.
-
-- Added getName() method to ParseResults.  This method is helpful when
-  a grammar specifies ZeroOrMore or OneOrMore of a MatchFirst or Or
-  expression, and the parsing code needs to know which expression matched.
-  (Thanks, Eric van der Vlist, for this idea!)
-
-- Added items() and values() methods to ParseResults, to better support using
-  ParseResults as a Dictionary.
-
-- Added parseFile() as a convenience function to parse the contents of an
-  entire text file.  Accepts either a file name or a file object.  (Thanks
-  again, Dang!)
-
-- Added group() method to And, Or, and MatchFirst, as a short-cut alternative
-  to enclosing a construct inside a Group object.
-
-- Extended fourFn.py to support exponentiation, and simple built-in functions.
-
-- Added EBNF parser to examples, including a demo where it parses its own
-  EBNF!  (Thanks to Seo Sanghyeon!)
-
-- Added Delphi Form parser to examples, dfmparse.py, plus a couple of
-  sample Delphi forms as tests.  (Well done, Dang!)
-
-- Another performance speedup, 5-10%, inspired by Dang!  Plus about a 20%
-  speedup, by pre-constructing and cacheing exception objects instead of
-  constructing them on the fly.
-
-- Fixed minor bug when specifying oneOf() with 'caseless=True'.
-
-- Cleaned up and added a few more docstrings, to improve the generated docs.
-
-
-Version 1.1.2 - 21 Mar 2004
----------------------------
-- Fixed minor bug in scanString(), so that start location is at the start of
-  the matched tokens, not at the start of the whitespace before the matched
-  tokens.
-
-- Inclusion of HTML documentation, generated using Epydoc.  Reformatted some
-  doc strings to better generate readable docs. (Beautiful work, Ed Loper,
-  thanks for Epydoc!)
-
-- Minor performance speedup, 5-15%
-
-- And on a process note, I've used the unittest module to define a series of
-  unit tests, to help avoid the embarrassment of the version 1.1 snafu.
-
-
-Version 1.1.1 - 6 Mar 2004
---------------------------
-- Fixed critical bug introduced in 1.1, which broke MatchFirst(!) token
-  matching.
-  **THANK YOU, SEO SANGHYEON!!!**
-
-- Added "from future import __generators__" to permit running under
-  pre-Python 2.3.
-
-- Added example getNTPservers.py, showing how to use pyparsing to extract
-  a text pattern from the HTML of a web page.
-
-
-Version 1.1 - 3 Mar 2004
--------------------------
-- ***Changed API*** - While testing out parse actions, I found that the value
-  of loc passed in was not the starting location of the matched tokens, but
-  the location of the next token in the list.  With this version, the location
-  passed to the parse action is now the starting location of the tokens that
-  matched.
-
-  A second part of this change is that the return value of parse actions no
-  longer needs to return a tuple containing both the location and the parsed
-  tokens (which may optionally be modified); parse actions only need to return
-  the list of tokens.  Parse actions that return a tuple are deprecated; they
-  will still work properly for conversion/compatibility, but this behavior will
-  be removed in a future version.
-
-- Added validate() method, to help diagnose infinite recursion in a grammar tree.
-  validate() is not 100% fool-proof, but it can help track down nasty infinite
-  looping due to recursively referencing the same grammar construct without some
-  intervening characters.
-
-- Cleaned up default listing of some parse element types, to more closely match
-  ordinary BNF.  Instead of the form <classname>:[contents-list], some changes
-  are:
-  . And(token1,token2,token3) is "{ token1 token2 token3 }"
-  . Or(token1,token2,token3) is "{ token1 ^ token2 ^ token3 }"
-  . MatchFirst(token1,token2,token3) is "{ token1 | token2 | token3 }"
-  . Optional(token) is "[ token ]"
-  . OneOrMore(token) is "{ token }..."
-  . ZeroOrMore(token) is "[ token ]..."
-
-- Fixed an infinite loop in oneOf if the input string contains a duplicated
-  option. (Thanks Brad Clements)
-
-- Fixed a bug when specifying a results name on an Optional token. (Thanks
-  again, Brad Clements)
-
-- Fixed a bug introduced in 1.0.6 when I converted quotedString to use
-  CharsNotIn; I accidentally permitted quoted strings to span newlines.  I have
-  fixed this in this version to go back to the original behavior, in which
-  quoted strings do *not* span newlines.
-
-- Fixed minor bug in HTTP server log parser. (Thanks Jim Richardson)
-
-
-Version 1.0.6 -  13 Feb 2004
-----------------------------
-- Added CharsNotIn class (Thanks, Lee SangYeong).  This is the opposite of
-  Word, in that it is constructed with a set of characters *not* to be matched.
-  (This enhancement also allowed me to clean up and simplify some of the
-  definitions for quoted strings, cStyleComment, and restOfLine.)
-
-- **MINOR API CHANGE** - Added joinString argument to the __init__ method of
-  Combine (Thanks, Thomas Kalka).  joinString defaults to "", but some
-  applications might choose some other string to use instead, such as a blank
-  or newline.  joinString was inserted as the second argument to __init__,
-  so if you have code that specifies an adjacent value, without using
-  'adjacent=', this code will break.
-
-- Modified LineStart to recognize the start of an empty line.
-
-- Added optional caseless flag to oneOf(), to create a list of CaselessLiteral
-  tokens instead of Literal tokens.
-
-- Added some enhancements to the SQL example:
-  . Oracle-style comments (Thanks to Harald Armin Massa)
-  . simple WHERE clause
-
-- Minor performance speedup - 5-15%
-
-
-Version 1.0.5 -  19 Jan 2004
-----------------------------
-- Added scanString() generator method to ParseElement, to support regex-like
-  pattern-searching
-
-- Added items() list to ParseResults, to return named results as a
-  list of (key,value) pairs
-
-- Fixed memory overflow in asList() for deeply nested ParseResults (Thanks,
-  Sverrir Valgeirsson)
-
-- Minor performance speedup - 10-15%
-
-
-Version 1.0.4 -  8 Jan 2004
----------------------------
-- Added positional tokens StringStart, StringEnd, LineStart, and LineEnd
-
-- Added commaSeparatedList to pre-defined global token definitions; also added
-  commasep.py to the examples directory, to demonstrate the differences between
-  parsing comma-separated data and simple line-splitting at commas
-
-- Minor API change: delimitedList does not automatically enclose the
-  list elements in a Group, but makes this the responsibility of the caller;
-  also, if invoked using 'combine=True', the list delimiters are also included
-  in the returned text (good for scoped variables, such as a.b.c or a::b::c, or
-  for directory paths such as a/b/c)
-
-- Performance speed-up again, 30-40%
-
-- Added httpServerLogParser.py to examples directory, as this is
-  a common parsing task
-
-
-Version 1.0.3 - 23 Dec 2003
----------------------------
-- Performance speed-up again, 20-40%
-
-- Added Python distutils installation setup.py, etc. (thanks, Dave Kuhlman)
-
-
-Version 1.0.2 - 18 Dec 2003
----------------------------
-- **NOTE: Changed API again!!!** (for the last time, I hope)
-
-  + Renamed module from parsing to pyparsing, to better reflect Python
-    linkage.
-
-- Also added dictExample.py to examples directory, to illustrate
-  usage of the Dict class.
-
-
-Version 1.0.1 - 17 Dec 2003
----------------------------
-- **NOTE:  Changed API!**
-
-  + Renamed 'len' argument on Word.__init__() to 'exact'
-
-- Performance speed-up, 10-30%
-
-
-Version 1.0.0 - 15 Dec 2003
----------------------------
-- Initial public release
-
-Version 0.1.1 thru 0.1.17 - October-November, 2003
---------------------------------------------------
-- initial development iterations:
-    - added Dict, Group
-    - added helper methods oneOf, delimitedList
-    - added helpers quotedString (and double and single), restOfLine, cStyleComment
-    - added MatchFirst as an alternative to the slower Or
-    - added UML class diagram
-    - fixed various logic bugs
diff --git a/src/HowToUsePyparsing.html b/src/HowToUsePyparsing.html
deleted file mode 100644
--- a/src/HowToUsePyparsing.html
+++ /dev/null
@@ -1,1288 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.8: http://docutils.sourceforge.net/" />
-<title>Using the pyparsing module</title>
-<meta name="author" content="Paul McGuire" />
-<meta name="date" content="June, 2011" />
-<meta name="copyright" content="Copyright © 2003-2011 Paul McGuire." />
-<style type="text/css">
-
-/*
-:Author: David Goodger (goodger@python.org)
-:Id: $Id: html4css1.css 6387 2010-08-13 12:23:41Z milde $
-:Copyright: This stylesheet has been placed in the public domain.
-
-Default cascading style sheet for the HTML output of Docutils.
-
-See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
-customize this style sheet.
-*/
-
-/* used to remove borders from tables and images */
-.borderless, table.borderless td, table.borderless th {
-  border: 0 }
-
-table.borderless td, table.borderless th {
-  /* Override padding for "table.docutils td" with "! important".
-     The right padding separates the table cells. */
-  padding: 0 0.5em 0 0 ! important }
-
-.first {
-  /* Override more specific margin styles with "! important". */
-  margin-top: 0 ! important }
-
-.last, .with-subtitle {
-  margin-bottom: 0 ! important }
-
-.hidden {
-  display: none }
-
-a.toc-backref {
-  text-decoration: none ;
-  color: black }
-
-blockquote.epigraph {
-  margin: 2em 5em ; }
-
-dl.docutils dd {
-  margin-bottom: 0.5em }
-
-object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
-  overflow: hidden;
-}
-
-/* Uncomment (and remove this text!) to get bold-faced definition list terms
-dl.docutils dt {
-  font-weight: bold }
-*/
-
-div.abstract {
-  margin: 2em 5em }
-
-div.abstract p.topic-title {
-  font-weight: bold ;
-  text-align: center }
-
-div.admonition, div.attention, div.caution, div.danger, div.error,
-div.hint, div.important, div.note, div.tip, div.warning {
-  margin: 2em ;
-  border: medium outset ;
-  padding: 1em }
-
-div.admonition p.admonition-title, div.hint p.admonition-title,
-div.important p.admonition-title, div.note p.admonition-title,
-div.tip p.admonition-title {
-  font-weight: bold ;
-  font-family: sans-serif }
-
-div.attention p.admonition-title, div.caution p.admonition-title,
-div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title {
-  color: red ;
-  font-weight: bold ;
-  font-family: sans-serif }
-
-/* Uncomment (and remove this text!) to get reduced vertical space in
-   compound paragraphs.
-div.compound .compound-first, div.compound .compound-middle {
-  margin-bottom: 0.5em }
-
-div.compound .compound-last, div.compound .compound-middle {
-  margin-top: 0.5em }
-*/
-
-div.dedication {
-  margin: 2em 5em ;
-  text-align: center ;
-  font-style: italic }
-
-div.dedication p.topic-title {
-  font-weight: bold ;
-  font-style: normal }
-
-div.figure {
-  margin-left: 2em ;
-  margin-right: 2em }
-
-div.footer, div.header {
-  clear: both;
-  font-size: smaller }
-
-div.line-block {
-  display: block ;
-  margin-top: 1em ;
-  margin-bottom: 1em }
-
-div.line-block div.line-block {
-  margin-top: 0 ;
-  margin-bottom: 0 ;
-  margin-left: 1.5em }
-
-div.sidebar {
-  margin: 0 0 0.5em 1em ;
-  border: medium outset ;
-  padding: 1em ;
-  background-color: #ffffee ;
-  width: 40% ;
-  float: right ;
-  clear: right }
-
-div.sidebar p.rubric {
-  font-family: sans-serif ;
-  font-size: medium }
-
-div.system-messages {
-  margin: 5em }
-
-div.system-messages h1 {
-  color: red }
-
-div.system-message {
-  border: medium outset ;
-  padding: 1em }
-
-div.system-message p.system-message-title {
-  color: red ;
-  font-weight: bold }
-
-div.topic {
-  margin: 2em }
-
-h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
-h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
-  margin-top: 0.4em }
-
-h1.title {
-  text-align: center }
-
-h2.subtitle {
-  text-align: center }
-
-hr.docutils {
-  width: 75% }
-
-img.align-left, .figure.align-left, object.align-left {
-  clear: left ;
-  float: left ;
-  margin-right: 1em }
-
-img.align-right, .figure.align-right, object.align-right {
-  clear: right ;
-  float: right ;
-  margin-left: 1em }
-
-img.align-center, .figure.align-center, object.align-center {
-  display: block;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-.align-left {
-  text-align: left }
-
-.align-center {
-  clear: both ;
-  text-align: center }
-
-.align-right {
-  text-align: right }
-
-/* reset inner alignment in figures */
-div.align-right {
-  text-align: left }
-
-/* div.align-center * { */
-/*   text-align: left } */
-
-ol.simple, ul.simple {
-  margin-bottom: 1em }
-
-ol.arabic {
-  list-style: decimal }
-
-ol.loweralpha {
-  list-style: lower-alpha }
-
-ol.upperalpha {
-  list-style: upper-alpha }
-
-ol.lowerroman {
-  list-style: lower-roman }
-
-ol.upperroman {
-  list-style: upper-roman }
-
-p.attribution {
-  text-align: right ;
-  margin-left: 50% }
-
-p.caption {
-  font-style: italic }
-
-p.credits {
-  font-style: italic ;
-  font-size: smaller }
-
-p.label {
-  white-space: nowrap }
-
-p.rubric {
-  font-weight: bold ;
-  font-size: larger ;
-  color: maroon ;
-  text-align: center }
-
-p.sidebar-title {
-  font-family: sans-serif ;
-  font-weight: bold ;
-  font-size: larger }
-
-p.sidebar-subtitle {
-  font-family: sans-serif ;
-  font-weight: bold }
-
-p.topic-title {
-  font-weight: bold }
-
-pre.address {
-  margin-bottom: 0 ;
-  margin-top: 0 ;
-  font: inherit }
-
-pre.literal-block, pre.doctest-block {
-  margin-left: 2em ;
-  margin-right: 2em }
-
-span.classifier {
-  font-family: sans-serif ;
-  font-style: oblique }
-
-span.classifier-delimiter {
-  font-family: sans-serif ;
-  font-weight: bold }
-
-span.interpreted {
-  font-family: sans-serif }
-
-span.option {
-  white-space: nowrap }
-
-span.pre {
-  white-space: pre }
-
-span.problematic {
-  color: red }
-
-span.section-subtitle {
-  /* font-size relative to parent (h1..h6 element) */
-  font-size: 80% }
-
-table.citation {
-  border-left: solid 1px gray;
-  margin-left: 1px }
-
-table.docinfo {
-  margin: 2em 4em }
-
-table.docutils {
-  margin-top: 0.5em ;
-  margin-bottom: 0.5em }
-
-table.footnote {
-  border-left: solid 1px black;
-  margin-left: 1px }
-
-table.docutils td, table.docutils th,
-table.docinfo td, table.docinfo th {
-  padding-left: 0.5em ;
-  padding-right: 0.5em ;
-  vertical-align: top }
-
-table.docutils th.field-name, table.docinfo th.docinfo-name {
-  font-weight: bold ;
-  text-align: left ;
-  white-space: nowrap ;
-  padding-left: 0 }
-
-h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
-h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
-  font-size: 100% }
-
-ul.auto-toc {
-  list-style-type: none }
-
-</style>
-</head>
-<body>
-<div class="document" id="using-the-pyparsing-module">
-<h1 class="title">Using the pyparsing module</h1>
-<table class="docinfo" frame="void" rules="none">
-<col class="docinfo-name" />
-<col class="docinfo-content" />
-<tbody valign="top">
-<tr><th class="docinfo-name">Author:</th>
-<td>Paul McGuire</td></tr>
-<tr><th class="docinfo-name">Address:</th>
-<td><pre class="address">
-<a class="first last reference external" href="mailto:ptmcg&#64;users.sourceforge.net">ptmcg&#64;users.sourceforge.net</a>
-</pre>
-</td></tr>
-<tr><th class="docinfo-name">Revision:</th>
-<td>1.5.6</td></tr>
-<tr><th class="docinfo-name">Date:</th>
-<td>June, 2011</td></tr>
-<tr><th class="docinfo-name">Copyright:</th>
-<td>Copyright © 2003-2011 Paul McGuire.</td></tr>
-</tbody>
-</table>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">abstract:</th><td class="field-body">This document provides how-to instructions for the
-pyparsing library, an easy-to-use Python module for constructing
-and executing basic text parsers.  The pyparsing module is useful
-for evaluating user-definable
-expressions, processing custom application language commands, or
-extracting data from formatted reports.</td>
-</tr>
-</tbody>
-</table>
-<div class="contents topic" id="contents">
-<p class="topic-title first">Contents</p>
-<ul class="auto-toc simple">
-<li><a class="reference internal" href="#steps-to-follow" id="id1">1&nbsp;&nbsp;&nbsp;Steps to follow</a><ul class="auto-toc">
-<li><a class="reference internal" href="#hello-world" id="id2">1.1&nbsp;&nbsp;&nbsp;Hello, World!</a></li>
-<li><a class="reference internal" href="#usage-notes" id="id3">1.2&nbsp;&nbsp;&nbsp;Usage notes</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#classes" id="id4">2&nbsp;&nbsp;&nbsp;Classes</a><ul class="auto-toc">
-<li><a class="reference internal" href="#classes-in-the-pyparsing-module" id="id5">2.1&nbsp;&nbsp;&nbsp;Classes in the pyparsing module</a></li>
-<li><a class="reference internal" href="#basic-parserelement-subclasses" id="id6">2.2&nbsp;&nbsp;&nbsp;Basic ParserElement subclasses</a></li>
-<li><a class="reference internal" href="#expression-subclasses" id="id7">2.3&nbsp;&nbsp;&nbsp;Expression subclasses</a></li>
-<li><a class="reference internal" href="#expression-operators" id="id8">2.4&nbsp;&nbsp;&nbsp;Expression operators</a></li>
-<li><a class="reference internal" href="#positional-subclasses" id="id9">2.5&nbsp;&nbsp;&nbsp;Positional subclasses</a></li>
-<li><a class="reference internal" href="#converter-subclasses" id="id10">2.6&nbsp;&nbsp;&nbsp;Converter subclasses</a></li>
-<li><a class="reference internal" href="#special-subclasses" id="id11">2.7&nbsp;&nbsp;&nbsp;Special subclasses</a></li>
-<li><a class="reference internal" href="#other-classes" id="id12">2.8&nbsp;&nbsp;&nbsp;Other classes</a></li>
-<li><a class="reference internal" href="#exception-classes-and-troubleshooting" id="id13">2.9&nbsp;&nbsp;&nbsp;Exception classes and Troubleshooting</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#miscellaneous-attributes-and-methods" id="id14">3&nbsp;&nbsp;&nbsp;Miscellaneous attributes and methods</a><ul class="auto-toc">
-<li><a class="reference internal" href="#helper-methods" id="id15">3.1&nbsp;&nbsp;&nbsp;Helper methods</a></li>
-<li><a class="reference internal" href="#helper-parse-actions" id="id16">3.2&nbsp;&nbsp;&nbsp;Helper parse actions</a></li>
-<li><a class="reference internal" href="#common-string-and-token-constants" id="id17">3.3&nbsp;&nbsp;&nbsp;Common string and token constants</a></li>
-</ul>
-</li>
-</ul>
-</div>
-<div class="section" id="steps-to-follow">
-<h1><a class="toc-backref" href="#id1">1&nbsp;&nbsp;&nbsp;Steps to follow</a></h1>
-<p>To parse an incoming data string, the client code must follow these steps:</p>
-<ol class="arabic simple">
-<li>First define the tokens and patterns to be matched, and assign
-this to a program variable.  Optional results names or parsing
-actions can also be defined at this time.</li>
-<li>Call <tt class="docutils literal">parseString()</tt> or <tt class="docutils literal">scanString()</tt> on this variable, passing in
-the string to
-be parsed.  During the matching process, whitespace between
-tokens is skipped by default (although this can be changed).
-When token matches occur, any defined parse action methods are
-called.</li>
-<li>Process the parsed results, returned as a list of strings.
-Matching results may also be accessed as named attributes of
-the returned results, if names are defined in the definition of
-the token pattern, using <tt class="docutils literal">setResultsName()</tt>.</li>
-</ol>
-<div class="section" id="hello-world">
-<h2><a class="toc-backref" href="#id2">1.1&nbsp;&nbsp;&nbsp;Hello, World!</a></h2>
-<p>The following complete Python program will parse the greeting &quot;Hello, World!&quot;,
-or any other greeting of the form &quot;&lt;salutation&gt;, &lt;addressee&gt;!&quot;:</p>
-<pre class="literal-block">
-from pyparsing import Word, alphas
-
-greet = Word( alphas ) + &quot;,&quot; + Word( alphas ) + &quot;!&quot;
-greeting = greet.parseString( &quot;Hello, World!&quot; )
-print greeting
-</pre>
-<p>The parsed tokens are returned in the following form:</p>
-<pre class="literal-block">
-['Hello', ',', 'World', '!']
-</pre>
-</div>
-<div class="section" id="usage-notes">
-<h2><a class="toc-backref" href="#id3">1.2&nbsp;&nbsp;&nbsp;Usage notes</a></h2>
-<ul>
-<li><p class="first">The pyparsing module can be used to interpret simple command
-strings or algebraic expressions, or can be used to extract data
-from text reports with complicated format and structure (&quot;screen
-or report scraping&quot;).  However, it is possible that your defined
-matching patterns may accept invalid inputs.  Use pyparsing to
-extract data from strings assumed to be well-formatted.</p>
-</li>
-<li><p class="first">To keep up the readability of your code, use <a class="reference internal" href="#operators">operators</a>  such as <tt class="docutils literal">+</tt>, <tt class="docutils literal">|</tt>,
-<tt class="docutils literal">^</tt>, and <tt class="docutils literal">~</tt> to combine expressions.  You can also combine
-string literals with ParseExpressions - they will be
-automatically converted to Literal objects.  For example:</p>
-<pre class="literal-block">
-integer  = Word( nums )            # simple unsigned integer
-variable = Word( alphas, max=1 )   # single letter variable, such as x, z, m, etc.
-arithOp  = Word( &quot;+-*/&quot;, max=1 )   # arithmetic operators
-equation = variable + &quot;=&quot; + integer + arithOp + integer    # will match &quot;x=2+2&quot;, etc.
-</pre>
-<p>In the definition of <tt class="docutils literal">equation</tt>, the string <tt class="docutils literal">&quot;=&quot;</tt> will get added as
-a <tt class="docutils literal"><span class="pre">Literal(&quot;=&quot;)</span></tt>, but in a more readable way.</p>
-</li>
-<li><p class="first">The pyparsing module's default behavior is to ignore whitespace.  This is the
-case for 99% of all parsers ever written.  This allows you to write simple, clean,
-grammars, such as the above <tt class="docutils literal">equation</tt>, without having to clutter it up with
-extraneous <tt class="docutils literal">ws</tt> markers.  The <tt class="docutils literal">equation</tt> grammar will successfully parse all of the
-following statements:</p>
-<pre class="literal-block">
-x=2+2
-x = 2+2
-a = 10   *   4
-r= 1234/ 100000
-</pre>
-<p>Of course, it is quite simple to extend this example to support more elaborate expressions, with
-nesting with parentheses, floating point numbers, scientific notation, and named constants
-(such as <tt class="docutils literal">e</tt> or <tt class="docutils literal">pi</tt>).  See <tt class="docutils literal">fourFn.py</tt>, included in the examples directory.</p>
-</li>
-<li><p class="first">To modify pyparsing's default whitespace skipping, you can use one or
-more of the following methods:</p>
-<ul>
-<li><p class="first">use the static method <tt class="docutils literal">ParserElement.setDefaultWhitespaceChars</tt>
-to override the normal set of whitespace chars (' tn').  For instance
-when defining a grammar in which newlines are significant, you should
-call <tt class="docutils literal">ParserElement.setDefaultWhitespaceChars(' \t')</tt> to remove
-newline from the set of skippable whitespace characters.  Calling
-this method will affect all pyparsing expressions defined afterward.</p>
-</li>
-<li><p class="first">call <tt class="docutils literal">leaveWhitespace()</tt> on individual expressions, to suppress the
-skipping of whitespace before trying to match the expression</p>
-</li>
-<li><p class="first">use <tt class="docutils literal">Combine</tt> to require that successive expressions must be
-adjacent in the input string.  For instance, this expression:</p>
-<pre class="literal-block">
-real = Word(nums) + '.' + Word(nums)
-</pre>
-<p>will match &quot;3.14159&quot;, but will also match &quot;3 . 12&quot;.  It will also
-return the matched results as ['3', '.', '14159'].  By changing this
-expression to:</p>
-<pre class="literal-block">
-real = Combine( Word(nums) + '.' + Word(nums) )
-</pre>
-<p>it will not match numbers with embedded spaces, and it will return a
-single concatenated string '3.14159' as the parsed token.</p>
-</li>
-</ul>
-</li>
-<li><p class="first">Repetition of expressions can be indicated using the '*' operator.  An
-expression may be multiplied by an integer value (to indicate an exact
-repetition count), or by a tuple containing
-two integers, or None and an integer, representing min and max repetitions
-(with None representing no min or no max, depending whether it is the first or
-second tuple element).  See the following examples, where n is used to
-indicate an integer value:</p>
-<ul class="simple">
-<li><tt class="docutils literal">expr*3</tt> is equivalent to <tt class="docutils literal">expr + expr + expr</tt></li>
-<li><tt class="docutils literal"><span class="pre">expr*(2,3)</span></tt> is equivalent to <tt class="docutils literal">expr + expr + Optional(expr)</tt></li>
-<li><tt class="docutils literal"><span class="pre">expr*(n,None)</span></tt> or <tt class="docutils literal"><span class="pre">expr*(n,)</span></tt> is equivalent
-to <tt class="docutils literal">expr*n + ZeroOrMore(expr)</tt> (read as &quot;at least n instances of expr&quot;)</li>
-<li><tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">expr*(0,n)</span></tt>
-(read as &quot;0 to n instances of expr&quot;)</li>
-<li><tt class="docutils literal"><span class="pre">expr*(None,None)</span></tt> is equivalent to <tt class="docutils literal">ZeroOrMore(expr)</tt></li>
-<li><tt class="docutils literal"><span class="pre">expr*(1,None)</span></tt> is equivalent to <tt class="docutils literal">OneOrMore(expr)</tt></li>
-</ul>
-<p>Note that <tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> does not raise an exception if
-more than n exprs exist in the input stream; that is,
-<tt class="docutils literal"><span class="pre">expr*(None,n)</span></tt> does not enforce a maximum number of expr
-occurrences.  If this behavior is desired, then write
-<tt class="docutils literal"><span class="pre">expr*(None,n)</span> + ~expr</tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">MatchFirst</tt> expressions are matched left-to-right, and the first
-match found will skip all later expressions within, so be sure
-to define less-specific patterns after more-specific patterns.
-If you are not sure which expressions are most specific, use Or
-expressions (defined using the <tt class="docutils literal">^</tt> operator) - they will always
-match the longest expression, although they are more
-compute-intensive.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">Or</tt> expressions will evaluate all of the specified subexpressions
-to determine which is the &quot;best&quot; match, that is, which matches
-the longest string in the input data.  In case of a tie, the
-left-most expression in the <tt class="docutils literal">Or</tt> list will win.</p>
-</li>
-<li><p class="first">If parsing the contents of an entire file, pass it to the
-<tt class="docutils literal">parseFile</tt> method using:</p>
-<pre class="literal-block">
-expr.parseFile( sourceFile )
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">ParseExceptions</tt> will report the location where an expected token
-or expression failed to match.  For example, if we tried to use our
-&quot;Hello, World!&quot; parser to parse &quot;Hello World!&quot; (leaving out the separating
-comma), we would get an exception, with the message:</p>
-<pre class="literal-block">
-pyparsing.ParseException: Expected &quot;,&quot; (6), (1,7)
-</pre>
-<p>In the case of complex
-expressions, the reported location may not be exactly where you
-would expect.  See more information under <a class="reference internal" href="#parseexception">ParseException</a> .</p>
-</li>
-<li><p class="first">Use the <tt class="docutils literal">Group</tt> class to enclose logical groups of tokens within a
-sublist.  This will help organize your results into more
-hierarchical form (the default behavior is to return matching
-tokens as a flat list of matching input strings).</p>
-</li>
-<li><p class="first">Punctuation may be significant for matching, but is rarely of
-much interest in the parsed results.  Use the <tt class="docutils literal">suppress()</tt> method
-to keep these tokens from cluttering up your returned lists of
-tokens.  For example, <tt class="docutils literal">delimitedList()</tt> matches a succession of
-one or more expressions, separated by delimiters (commas by
-default), but only returns a list of the actual expressions -
-the delimiters are used for parsing, but are suppressed from the
-returned output.</p>
-</li>
-<li><p class="first">Parse actions can be used to convert values from strings to
-other data types (ints, floats, booleans, etc.).</p>
-</li>
-<li><p class="first">Results names are recommended for retrieving tokens from complex
-expressions.  It is much easier to access a token using its field
-name than using a positional index, especially if the expression
-contains optional elements.  You can also shortcut
-the <tt class="docutils literal">setResultsName</tt> call:</p>
-<pre class="literal-block">
-stats = &quot;AVE:&quot; + realNum.setResultsName(&quot;average&quot;) + \
-        &quot;MIN:&quot; + realNum.setResultsName(&quot;min&quot;) + \
-        &quot;MAX:&quot; + realNum.setResultsName(&quot;max&quot;)
-</pre>
-<p>can now be written as this:</p>
-<pre class="literal-block">
-stats = &quot;AVE:&quot; + realNum(&quot;average&quot;) + \
-        &quot;MIN:&quot; + realNum(&quot;min&quot;) + \
-        &quot;MAX:&quot; + realNum(&quot;max&quot;)
-</pre>
-</li>
-<li><p class="first">Be careful when defining parse actions that modify global variables or
-data structures (as in <tt class="docutils literal">fourFn.py</tt>), especially for low level tokens
-or expressions that may occur within an <tt class="docutils literal">And</tt> expression; an early element
-of an <tt class="docutils literal">And</tt> may match, but the overall expression may fail.</p>
-</li>
-<li><p class="first">Performance of pyparsing may be slow for complex grammars and/or large
-input strings.  The <a class="reference external" href="http://psyco.sourceforge.net/">psyco</a> package can be used to improve the speed of the
-pyparsing module with no changes to grammar or program logic - observed
-improvments have been in the 20-50% range.</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="section" id="classes">
-<h1><a class="toc-backref" href="#id4">2&nbsp;&nbsp;&nbsp;Classes</a></h1>
-<div class="section" id="classes-in-the-pyparsing-module">
-<h2><a class="toc-backref" href="#id5">2.1&nbsp;&nbsp;&nbsp;Classes in the pyparsing module</a></h2>
-<p><tt class="docutils literal">ParserElement</tt> - abstract base class for all pyparsing classes;
-methods for code to use are:</p>
-<ul>
-<li><p class="first"><tt class="docutils literal">parseString( sourceString, parseAll=False )</tt> - only called once, on the overall
-matching pattern; returns a <a class="reference internal" href="#parseresults">ParseResults</a> object that makes the
-matched tokens available as a list, and optionally as a dictionary,
-or as an object with named attributes; if parseAll is set to True, then
-parseString will raise a ParseException if the grammar does not process
-the complete input string.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">parseFile( sourceFile )</tt> - a convenience function, that accepts an
-input file object or filename.  The file contents are passed as a
-string to <tt class="docutils literal">parseString()</tt>.  <tt class="docutils literal">parseFile</tt> also supports the <tt class="docutils literal">parseAll</tt> argument.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">scanString( sourceString )</tt> - generator function, used to find and
-extract matching text in the given source string; for each matched text,
-returns a tuple of:</p>
-<ul class="simple">
-<li>matched tokens (packaged as a <a class="reference internal" href="#parseresults">ParseResults</a> object)</li>
-<li>start location of the matched text in the given source string</li>
-<li>end location in the given source string</li>
-</ul>
-<p><tt class="docutils literal">scanString</tt> allows you to scan through the input source string for
-random matches, instead of exhaustively defining the grammar for the entire
-source text (as would be required with <tt class="docutils literal">parseString</tt>).</p>
-</li>
-<li><p class="first"><tt class="docutils literal">transformString( sourceString )</tt> - convenience wrapper function for
-<tt class="docutils literal">scanString</tt>, to process the input source string, and replace matching
-text with the tokens returned from parse actions defined in the grammar
-(see <a class="reference internal" href="#setparseaction">setParseAction</a>).</p>
-</li>
-<li><p class="first"><tt class="docutils literal">searchString( sourceString )</tt> - another convenience wrapper function for
-<tt class="docutils literal">scanString</tt>, returns a list of the matching tokens returned from each
-call to <tt class="docutils literal">scanString</tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setName( name )</tt> - associate a short descriptive name for this
-element, useful in displaying exceptions and trace information</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setResultsName( string, listAllMatches=False )</tt> - name to be given
-to tokens matching
-the element; if multiple tokens within
-a repetition group (such as <tt class="docutils literal">ZeroOrMore</tt> or <tt class="docutils literal">delimitedList</tt>) the
-default is to return only the last matching token - if listAllMatches
-is set to True, then a list of all the matching tokens is returned.
-(New in 1.5.6 - a results name with a trailing '*' character will be
-interpreted as setting listAllMatches to True.)
-Note:
-<tt class="docutils literal">setResultsName</tt> returns a <em>copy</em> of the element so that a single
-basic element can be referenced multiple times and given
-different names within a complex grammar.</p>
-</li>
-</ul>
-<ul id="setparseaction">
-<li><p class="first"><tt class="docutils literal">setParseAction( *fn )</tt> - specify one or more functions to call after successful
-matching of the element; each function is defined as <tt class="docutils literal">fn( s,
-loc, toks )</tt>, where:</p>
-<ul class="simple">
-<li><tt class="docutils literal">s</tt> is the original parse string</li>
-<li><tt class="docutils literal">loc</tt> is the location in the string where matching started</li>
-<li><tt class="docutils literal">toks</tt> is the list of the matched tokens, packaged as a <a class="reference internal" href="#parseresults">ParseResults</a> object</li>
-</ul>
-<p>Multiple functions can be attached to a ParserElement by specifying multiple
-arguments to setParseAction, or by calling setParseAction multiple times.</p>
-<p>Each parse action function can return a modified <tt class="docutils literal">toks</tt> list, to perform conversion, or
-string modifications.  For brevity, <tt class="docutils literal">fn</tt> may also be a
-lambda - here is an example of using a parse action to convert matched
-integer tokens from strings to integers:</p>
-<pre class="literal-block">
-intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] )
-</pre>
-<p>If <tt class="docutils literal">fn</tt> does not modify the <tt class="docutils literal">toks</tt> list, it does not need to return
-anything at all.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setBreak( breakFlag=True )</tt> - if breakFlag is True, calls pdb.set_break()
-as this expression is about to be parsed</p>
-</li>
-<li><p class="first"><tt class="docutils literal">copy()</tt> - returns a copy of a ParserElement; can be used to use the same
-parse expression in different places in a grammar, with different parse actions
-attached to each</p>
-</li>
-<li><p class="first"><tt class="docutils literal">leaveWhitespace()</tt> - change default behavior of skipping
-whitespace before starting matching (mostly used internally to the
-pyparsing module, rarely used by client code)</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setWhitespaceChars( chars )</tt> - define the set of chars to be ignored
-as whitespace before trying to match a specific ParserElement, in place of the
-default set of whitespace (space, tab, newline, and return)</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setDefaultWhitespaceChars( chars )</tt> - class-level method to override
-the default set of whitespace chars for all subsequently created ParserElements
-(including copies); useful when defining grammars that treat one or more of the
-default whitespace characters as significant (such as a line-sensitive grammar, to
-omit newline from the list of ignorable whitespace)</p>
-</li>
-<li><p class="first"><tt class="docutils literal">suppress()</tt> - convenience function to suppress the output of the
-given element, instead of wrapping it with a Suppress object.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">ignore( expr )</tt> - function to specify parse expression to be
-ignored while matching defined patterns; can be called
-repeatedly to specify multiple expressions; useful to specify
-patterns of comment syntax, for example</p>
-</li>
-<li><p class="first"><tt class="docutils literal">setDebug( dbgFlag=True )</tt> - function to enable/disable tracing output
-when trying to match this element</p>
-</li>
-<li><p class="first"><tt class="docutils literal">validate()</tt> - function to verify that the defined grammar does not
-contain infinitely recursive constructs</p>
-</li>
-</ul>
-<ul class="simple" id="parsewithtabs">
-<li><tt class="docutils literal">parseWithTabs()</tt> - function to override default behavior of converting
-tabs to spaces before parsing the input string; rarely used, except when
-specifying whitespace-significant grammars using the <a class="reference internal" href="#white">White</a> class.</li>
-<li><tt class="docutils literal">enablePackrat()</tt> - a class-level static method to enable a memoizing
-performance enhancement, known as &quot;packrat parsing&quot;.  packrat parsing is
-disabled by default, since it may conflict with some user programs that use
-parse actions.  To activate the packrat feature, your
-program must call the class method ParserElement.enablePackrat().  If
-your program uses psyco to &quot;compile as you go&quot;, you must call
-enablePackrat before calling psyco.full().  If you do not do this,
-Python will crash.  For best results, call enablePackrat() immediately
-after importing pyparsing.</li>
-</ul>
-</div>
-<div class="section" id="basic-parserelement-subclasses">
-<h2><a class="toc-backref" href="#id6">2.2&nbsp;&nbsp;&nbsp;Basic ParserElement subclasses</a></h2>
-<ul class="simple">
-<li><tt class="docutils literal">Literal</tt> - construct with a string to be matched exactly</li>
-<li><tt class="docutils literal">CaselessLiteral</tt> - construct with a string to be matched, but
-without case checking; results are always returned as the
-defining literal, NOT as they are found in the input string</li>
-<li><tt class="docutils literal">Keyword</tt> - similar to Literal, but must be immediately followed by
-whitespace, punctuation, or other non-keyword characters; prevents
-accidental matching of a non-keyword that happens to begin with a
-defined keyword</li>
-<li><tt class="docutils literal">CaselessKeyword</tt> - similar to Keyword, but with caseless matching
-behavior</li>
-</ul>
-<ul id="word">
-<li><p class="first"><tt class="docutils literal">Word</tt> - one or more contiguous characters; construct with a
-string containing the set of allowed initial characters, and an
-optional second string of allowed body characters; for instance,
-a common Word construct is to match a code identifier - in C, a
-valid identifier must start with an alphabetic character or an
-underscore ('_'), followed by a body that can also include numeric
-digits.  That is, <tt class="docutils literal">a</tt>, <tt class="docutils literal">i</tt>, <tt class="docutils literal">MAX_LENGTH</tt>, <tt class="docutils literal">_a1</tt>, <tt class="docutils literal">b_109_</tt>, and
-<tt class="docutils literal">plan9FromOuterSpace</tt>
-are all valid identifiers; <tt class="docutils literal">9b7z</tt>, <tt class="docutils literal">$a</tt>, <tt class="docutils literal">.section</tt>, and <tt class="docutils literal">0debug</tt>
-are not.  To
-define an identifier using a Word, use either of the following:</p>
-<pre class="literal-block">
-- Word( alphas+&quot;_&quot;, alphanums+&quot;_&quot; )
-- Word( srange(&quot;[a-zA-Z_]&quot;), srange(&quot;[a-zA-Z0-9_]&quot;) )
-</pre>
-<p>If only one
-string given, it specifies that the same character set defined
-for the initial character is used for the word body; for instance, to
-define an identifier that can only be composed of capital letters and
-underscores, use:</p>
-<pre class="literal-block">
-- Word( &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ_&quot; )
-- Word( srange(&quot;[A-Z_]&quot;) )
-</pre>
-<p>A Word may
-also be constructed with any of the following optional parameters:</p>
-<ul class="simple">
-<li>min - indicating a minimum length of matching characters</li>
-<li>max - indicating a maximum length of matching characters</li>
-<li>exact - indicating an exact length of matching characters</li>
-</ul>
-<p>If exact is specified, it will override any values for min or max.</p>
-<p>New in 1.5.6 - Sometimes you want to define a word using all
-characters in a range except for one or two of them; you can do this
-with the new excludeChars argument. This is helpful if you want to define
-a word with all printables except for a single delimiter character, such
-as '.'. Previously, you would have to create a custom string to pass to Word.
-With this change, you can just create <tt class="docutils literal">Word(printables, <span class="pre">excludeChars='.')</span></tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">CharsNotIn</tt> - similar to <a class="reference internal" href="#word">Word</a>, but matches characters not
-in the given constructor string (accepts only one string for both
-initial and body characters); also supports min, max, and exact
-optional parameters.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">Regex</tt> - a powerful construct, that accepts a regular expression
-to be matched at the current parse position; accepts an optional
-flags parameter, corresponding to the flags parameter in the re.compile
-method; if the expression includes named sub-fields, they will be
-represented in the returned <a class="reference internal" href="#parseresults">ParseResults</a></p>
-</li>
-<li><p class="first"><tt class="docutils literal">QuotedString</tt> - supports the definition of custom quoted string
-formats, in addition to pyparsing's built-in dblQuotedString and
-sglQuotedString.  QuotedString allows you to specify the following
-parameters:</p>
-<ul class="simple">
-<li>quoteChar - string of one or more characters defining the quote delimiting string</li>
-<li>escChar - character to escape quotes, typically backslash (default=None)</li>
-<li>escQuote - special quote sequence to escape an embedded quote string (such as SQL's &quot;&quot; to escape an embedded &quot;) (default=None)</li>
-<li>multiline - boolean indicating whether quotes can span multiple lines (default=False)</li>
-<li>unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)</li>
-<li>endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None =&gt; same as quoteChar)</li>
-</ul>
-</li>
-<li><p class="first"><tt class="docutils literal">SkipTo</tt> - skips ahead in the input string, accepting any
-characters up to the specified pattern; may be constructed with
-the following optional parameters:</p>
-<ul class="simple">
-<li>include - if set to true, also consumes the match expression
-(default is false)</li>
-<li>ignore - allows the user to specify patterns to not be matched,
-to prevent false matches</li>
-<li>failOn - if a literal string or expression is given for this argument, it defines an expression that
-should cause the <tt class="docutils literal">SkipTo</tt> expression to fail, and not skip over that expression</li>
-</ul>
-</li>
-</ul>
-<ul class="simple" id="white">
-<li><tt class="docutils literal">White</tt> - also similar to <a class="reference internal" href="#word">Word</a>, but matches whitespace
-characters.  Not usually needed, as whitespace is implicitly
-ignored by pyparsing.  However, some grammars are whitespace-sensitive,
-such as those that use leading tabs or spaces to indicating grouping
-or hierarchy.  (If matching on tab characters, be sure to call
-<a class="reference internal" href="#parsewithtabs">parseWithTabs</a> on the top-level parse element.)</li>
-<li><tt class="docutils literal">Empty</tt> - a null expression, requiring no characters - will always
-match; useful for debugging and for specialized grammars</li>
-<li><tt class="docutils literal">NoMatch</tt> - opposite of Empty, will never match; useful for debugging
-and for specialized grammars</li>
-</ul>
-</div>
-<div class="section" id="expression-subclasses">
-<h2><a class="toc-backref" href="#id7">2.3&nbsp;&nbsp;&nbsp;Expression subclasses</a></h2>
-<ul>
-<li><p class="first"><tt class="docutils literal">And</tt> - construct with a list of ParserElements, all of which must
-match for And to match; can also be created using the '+'
-operator; multiple expressions can be Anded together using the '*'
-operator as in:</p>
-<pre class="literal-block">
-ipAddress = Word(nums) + ('.'+Word(nums))*3
-</pre>
-<p>A tuple can be used as the multiplier, indicating a min/max:</p>
-<pre class="literal-block">
-usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
-</pre>
-<p>A special form of <tt class="docutils literal">And</tt> is created if the '-' operator is used
-instead of the '+' operator.  In the ipAddress example above, if
-no trailing '.' and Word(nums) are found after matching the initial
-Word(nums), then pyparsing will back up in the grammar and try other
-alternatives to ipAddress.  However, if ipAddress is defined as:</p>
-<pre class="literal-block">
-strictIpAddress = Word(nums) - ('.'+Word(nums))*3
-</pre>
-<p>then no backing up is done.  If the first Word(nums) of strictIpAddress
-is matched, then any mismatch after that will raise a ParseSyntaxException,
-which will halt the parsing process immediately.  By careful use of the
-'-' operator, grammars can provide meaningful error messages close to
-the location where the incoming text does not match the specified
-grammar.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">Or</tt> - construct with a list of ParserElements, any of which must
-match for Or to match; if more than one expression matches, the
-expression that makes the longest match will be used; can also
-be created using the '^' operator</p>
-</li>
-<li><p class="first"><tt class="docutils literal">MatchFirst</tt> - construct with a list of ParserElements, any of
-which must match for MatchFirst to match; matching is done
-left-to-right, taking the first expression that matches; can
-also be created using the '|' operator</p>
-</li>
-<li><p class="first"><tt class="docutils literal">Each</tt> - similar to And, in that all of the provided expressions
-must match; however, Each permits matching to be done in any order;
-can also be created using the '&amp;' operator</p>
-</li>
-<li><p class="first"><tt class="docutils literal">Optional</tt> - construct with a ParserElement, but this element is
-not required to match; can be constructed with an optional <tt class="docutils literal">default</tt> argument,
-containing a default string or object to be supplied if the given optional
-parse element is not found in the input string; parse action will only
-be called if a match is found, or if a default is specified</p>
-</li>
-<li><p class="first"><tt class="docutils literal">ZeroOrMore</tt> - similar to Optional, but can be repeated</p>
-</li>
-<li><p class="first"><tt class="docutils literal">OneOrMore</tt> - similar to ZeroOrMore, but at least one match must
-be present</p>
-</li>
-<li><p class="first"><tt class="docutils literal">FollowedBy</tt> - a lookahead expression, requires matching of the given
-expressions, but does not advance the parsing position within the input string</p>
-</li>
-<li><p class="first"><tt class="docutils literal">NotAny</tt> - a negative lookahead expression, prevents matching of named
-expressions, does not advance the parsing position within the input string;
-can also be created using the unary '~' operator</p>
-</li>
-</ul>
-</div>
-<div class="section" id="expression-operators">
-<span id="operators"></span><h2><a class="toc-backref" href="#id8">2.4&nbsp;&nbsp;&nbsp;Expression operators</a></h2>
-<ul class="simple">
-<li><tt class="docutils literal">~</tt> - creates NotAny using the expression after the operator</li>
-<li><tt class="docutils literal">+</tt> - creates And using the expressions before and after the operator</li>
-<li><tt class="docutils literal">|</tt> - creates MatchFirst (first left-to-right match) using the expressions before and after the operator</li>
-<li><tt class="docutils literal">^</tt> - creates Or (longest match) using the expressions before and after the operator</li>
-<li><tt class="docutils literal">&amp;</tt> - creates Each using the expressions before and after the operator</li>
-<li><tt class="docutils literal">*</tt> - creates And by multiplying the expression by the integer operand; if
-expression is multiplied by a 2-tuple, creates an And of (min,max)
-expressions (similar to &quot;{min,max}&quot; form in regular expressions); if
-min is None, intepret as (0,max); if max is None, interpret as
-expr*min + ZeroOrMore(expr)</li>
-<li><tt class="docutils literal">-</tt> - like <tt class="docutils literal">+</tt> but with no backup and retry of alternatives</li>
-<li><tt class="docutils literal">*</tt> - repetition of expression</li>
-<li><tt class="docutils literal">==</tt> - matching expression to string; returns True if the string matches the given expression</li>
-<li><tt class="docutils literal">&lt;&lt;</tt> - inserts the expression following the operator as the body of the
-Forward expression before the operator</li>
-</ul>
-</div>
-<div class="section" id="positional-subclasses">
-<h2><a class="toc-backref" href="#id9">2.5&nbsp;&nbsp;&nbsp;Positional subclasses</a></h2>
-<ul class="simple">
-<li><tt class="docutils literal">StringStart</tt> - matches beginning of the text</li>
-<li><tt class="docutils literal">StringEnd</tt> - matches the end of the text</li>
-<li><tt class="docutils literal">LineStart</tt> - matches beginning of a line (lines delimited by <tt class="docutils literal">\n</tt> characters)</li>
-<li><tt class="docutils literal">LineEnd</tt> - matches the end of a line</li>
-<li><tt class="docutils literal">WordStart</tt> - matches a leading word boundary</li>
-<li><tt class="docutils literal">WordEnd</tt> - matches a trailing word boundary</li>
-</ul>
-</div>
-<div class="section" id="converter-subclasses">
-<h2><a class="toc-backref" href="#id10">2.6&nbsp;&nbsp;&nbsp;Converter subclasses</a></h2>
-<ul class="simple">
-<li><tt class="docutils literal">Upcase</tt> - converts matched tokens to uppercase (deprecated -
-use <tt class="docutils literal">upcaseTokens</tt> parse action instead)</li>
-<li><tt class="docutils literal">Combine</tt> - joins all matched tokens into a single string, using
-specified joinString (default <tt class="docutils literal"><span class="pre">joinString=&quot;&quot;</span></tt>); expects
-all matching tokens to be adjacent, with no intervening
-whitespace (can be overridden by specifying <tt class="docutils literal">adjacent=False</tt> in constructor)</li>
-<li><tt class="docutils literal">Suppress</tt> - clears matched tokens; useful to keep returned
-results from being cluttered with required but uninteresting
-tokens (such as list delimiters)</li>
-</ul>
-</div>
-<div class="section" id="special-subclasses">
-<h2><a class="toc-backref" href="#id11">2.7&nbsp;&nbsp;&nbsp;Special subclasses</a></h2>
-<ul class="simple">
-<li><tt class="docutils literal">Group</tt> - causes the matched tokens to be enclosed in a list;
-useful in repeated elements like <tt class="docutils literal">ZeroOrMore</tt> and <tt class="docutils literal">OneOrMore</tt> to
-break up matched tokens into groups for each repeated pattern</li>
-<li><tt class="docutils literal">Dict</tt> - like <tt class="docutils literal">Group</tt>, but also constructs a dictionary, using the
-[0]'th elements of all enclosed token lists as the keys, and
-each token list as the value</li>
-<li><tt class="docutils literal">SkipTo</tt> - catch-all matching expression that accepts all characters
-up until the given pattern is found to match; useful for specifying
-incomplete grammars</li>
-<li><tt class="docutils literal">Forward</tt> - placeholder token used to define recursive token
-patterns; when defining the actual expression later in the
-program, insert it into the <tt class="docutils literal">Forward</tt> object using the <tt class="docutils literal">&lt;&lt;</tt>
-operator (see <tt class="docutils literal">fourFn.py</tt> for an example).</li>
-</ul>
-</div>
-<div class="section" id="other-classes">
-<h2><a class="toc-backref" href="#id12">2.8&nbsp;&nbsp;&nbsp;Other classes</a></h2>
-<ul id="parseresults">
-<li><p class="first"><tt class="docutils literal">ParseResults</tt> - class used to contain and manage the lists of tokens
-created from parsing the input using the user-defined parse
-expression.  ParseResults can be accessed in a number of ways:</p>
-<ul class="simple">
-<li>as a list<ul>
-<li>total list of elements can be found using len()</li>
-<li>individual elements can be found using [0], [1], [-1], etc.</li>
-<li>elements can be deleted using <tt class="docutils literal">del</tt></li>
-<li>the -1th element can be extracted and removed in a single operation
-using <tt class="docutils literal">pop()</tt>, or any element can be extracted and removed
-using <tt class="docutils literal">pop(n)</tt></li>
-</ul>
-</li>
-<li>as a dictionary<ul>
-<li>if <tt class="docutils literal">setResultsName()</tt> is used to name elements within the
-overall parse expression, then these fields can be referenced
-as dictionary elements or as attributes</li>
-<li>the Dict class generates dictionary entries using the data of the
-input text - in addition to ParseResults listed as <tt class="docutils literal">[ [ a1, b1, c1, <span class="pre">...],</span> [ a2, b2, c2, <span class="pre">...]</span>&nbsp; ]</tt>
-it also acts as a dictionary with entries defined as <tt class="docutils literal">{ a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }</tt>;
-this is especially useful when processing tabular data where the first column contains a key
-value for that line of data</li>
-<li>list elements that are deleted using <tt class="docutils literal">del</tt> will still be accessible by their
-dictionary keys</li>
-<li>supports <tt class="docutils literal">get()</tt>, <tt class="docutils literal">items()</tt> and <tt class="docutils literal">keys()</tt> methods, similar to a dictionary</li>
-<li>a keyed item can be extracted and removed using <tt class="docutils literal">pop(key)</tt>.  Here
-key must be non-numeric (such as a string), in order to use dict
-extraction instead of list extraction.</li>
-<li>new named elements can be added (in a parse action, for instance), using the same
-syntax as adding an item to a dict (<tt class="docutils literal"><span class="pre">parseResults[&quot;X&quot;]=&quot;new</span> item&quot;</tt>); named elements can be removed using <tt class="docutils literal">del <span class="pre">parseResults[&quot;X&quot;]</span></tt></li>
-</ul>
-</li>
-<li>as a nested list<ul>
-<li>results returned from the Group class are encapsulated within their
-own list structure, so that the tokens can be handled as a hierarchical
-tree</li>
-</ul>
-</li>
-</ul>
-<p>ParseResults can also be converted to an ordinary list of strings
-by calling <tt class="docutils literal">asList()</tt>.  Note that this will strip the results of any
-field names that have been defined for any embedded parse elements.
-(The <tt class="docutils literal">pprint</tt> module is especially good at printing out the nested contents
-given by <tt class="docutils literal">asList()</tt>.)</p>
-<p>Finally, ParseResults can be converted to an XML string by calling <tt class="docutils literal">asXML()</tt>. Where
-possible, results will be tagged using the results names defined for the respective
-ParseExpressions.  <tt class="docutils literal">asXML()</tt> takes two optional arguments:</p>
-<ul class="simple">
-<li>doctagname - for ParseResults that do not have a defined name, this argument
-will wrap the resulting XML in a set of opening and closing tags <tt class="docutils literal">&lt;doctagname&gt;</tt>
-and <tt class="docutils literal">&lt;/doctagname&gt;</tt>.</li>
-<li>namedItemsOnly (default=False) - flag to indicate if the generated XML should
-skip items that do not have defined names.  If a nested group item is named, then all
-embedded items will be included, whether they have names or not.</li>
-</ul>
-</li>
-</ul>
-</div>
-<div class="section" id="exception-classes-and-troubleshooting">
-<h2><a class="toc-backref" href="#id13">2.9&nbsp;&nbsp;&nbsp;Exception classes and Troubleshooting</a></h2>
-<ul id="parseexception">
-<li><p class="first"><tt class="docutils literal">ParseException</tt> - exception returned when a grammar parse fails;
-ParseExceptions have attributes loc, msg, line, lineno, and column; to view the
-text line and location where the reported ParseException occurs, use:</p>
-<pre class="literal-block">
-except ParseException, err:
-    print err.line
-    print &quot; &quot;*(err.column-1) + &quot;^&quot;
-    print err
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">RecursiveGrammarException</tt> - exception returned by <tt class="docutils literal">validate()</tt> if
-the grammar contains a recursive infinite loop, such as:</p>
-<pre class="literal-block">
-badGrammar = Forward()
-goodToken = Literal(&quot;A&quot;)
-badGrammar &lt;&lt; Optional(goodToken) + badGrammar
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">ParseFatalException</tt> - exception that parse actions can raise to stop parsing
-immediately.  Should be used when a semantic error is found in the input text, such
-as a mismatched XML tag.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">ParseSyntaxException</tt> - subclass of <tt class="docutils literal">ParseFatalException</tt> raised when a
-syntax error is found, based on the use of the '-' operator when defining
-a sequence of expressions in an <tt class="docutils literal">And</tt> expression.</p>
-</li>
-</ul>
-<p>You can also get some insights into the parsing logic using diagnostic parse actions,
-and setDebug(), or test the matching of expression fragments by testing them using
-scanString().</p>
-</div>
-</div>
-<div class="section" id="miscellaneous-attributes-and-methods">
-<h1><a class="toc-backref" href="#id14">3&nbsp;&nbsp;&nbsp;Miscellaneous attributes and methods</a></h1>
-<div class="section" id="helper-methods">
-<h2><a class="toc-backref" href="#id15">3.1&nbsp;&nbsp;&nbsp;Helper methods</a></h2>
-<ul>
-<li><p class="first"><tt class="docutils literal">delimitedList( expr, <span class="pre">delim=',')</span></tt> - convenience function for
-matching one or more occurrences of expr, separated by delim.
-By default, the delimiters are suppressed, so the returned results contain
-only the separate list elements.  Can optionally specify <tt class="docutils literal">combine=True</tt>,
-indicating that the expressions and delimiters should be returned as one
-combined value (useful for scoped variables, such as &quot;a.b.c&quot;, or
-&quot;a::b::c&quot;, or paths such as &quot;a/b/c&quot;).</p>
-</li>
-<li><p class="first"><tt class="docutils literal">countedArray( expr )</tt> - convenience function for a pattern where an list of
-instances of the given expression are preceded by an integer giving the count of
-elements in the list.  Returns an expression that parses the leading integer,
-reads exactly that many expressions, and returns the array of expressions in the
-parse results - the leading integer is suppressed from the results (although it
-is easily reconstructed by using len on the returned array).</p>
-</li>
-<li><p class="first"><tt class="docutils literal">oneOf( string, caseless=False )</tt> - convenience function for quickly declaring an
-alternative set of <tt class="docutils literal">Literal</tt> tokens, by splitting the given string on
-whitespace boundaries.  The tokens are sorted so that longer
-matches are attempted first; this ensures that a short token does
-not mask a longer one that starts with the same characters. If <tt class="docutils literal">caseless=True</tt>,
-will create an alternative set of CaselessLiteral tokens.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">dictOf( key, value )</tt> - convenience function for quickly declaring a
-dictionary pattern of <tt class="docutils literal">Dict( ZeroOrMore( Group( key + value ) ) )</tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">makeHTMLTags( tagName )</tt> and <tt class="docutils literal">makeXMLTags( tagName )</tt> - convenience
-functions to create definitions of opening and closing tag expressions.  Returns
-a pair of expressions, for the corresponding &lt;tag&gt; and &lt;/tag&gt; strings.  Includes
-support for attributes in the opening tag, such as &lt;tag attr1=&quot;abc&quot;&gt; - attributes
-are returned as keyed tokens in the returned ParseResults.  <tt class="docutils literal">makeHTMLTags</tt> is less
-restrictive than <tt class="docutils literal">makeXMLTags</tt>, especially with respect to case sensitivity.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">operatorPrecedence(baseOperand, operatorList)</tt> - convenience function to define a
-grammar for parsing
-expressions with a hierarchical precedence of operators. To use the operatorPrecedence
-helper:</p>
-<ol class="arabic simple">
-<li>Define the base &quot;atom&quot; operand term of the grammar.
-For this simple grammar, the smallest operand is either
-and integer or a variable.  This will be the first argument
-to the operatorPrecedence method.</li>
-<li>Define a list of tuples for each level of operator
-precendence.  Each tuple is of the form
-<tt class="docutils literal">(opExpr, numTerms, rightLeftAssoc, parseAction)</tt>, where:<ul>
-<li>opExpr is the pyparsing expression for the operator;
-may also be a string, which will be converted to a Literal; if
-None, indicates an empty operator, such as the implied
-multiplication operation between 'm' and 'x' in &quot;y = mx + b&quot;.</li>
-<li>numTerms is the number of terms for this operator (must
-be 1 or 2)</li>
-<li>rightLeftAssoc is the indicator whether the operator is
-right or left associative, using the pyparsing-defined
-constants <tt class="docutils literal">opAssoc.RIGHT</tt> and <tt class="docutils literal">opAssoc.LEFT</tt>.</li>
-<li>parseAction is the parse action to be associated with
-expressions matching this operator expression (the
-parse action tuple member may be omitted)</li>
-</ul>
-</li>
-<li>Call operatorPrecedence passing the operand expression and
-the operator precedence list, and save the returned value
-as the generated pyparsing expression.  You can then use
-this expression to parse input strings, or incorporate it
-into a larger, more complex grammar.</li>
-</ol>
-</li>
-<li><p class="first"><tt class="docutils literal">matchPreviousLiteral</tt> and <tt class="docutils literal">matchPreviousExpr</tt> - function to define and
-expression that matches the same content
-as was parsed in a previous parse expression.  For instance:</p>
-<pre class="literal-block">
-first = Word(nums)
-matchExpr = first + &quot;:&quot; + matchPreviousLiteral(first)
-</pre>
-<p>will match &quot;1:1&quot;, but not &quot;1:2&quot;.  Since this matches at the literal
-level, this will also match the leading &quot;1:1&quot; in &quot;1:10&quot;.</p>
-<p>In contrast:</p>
-<pre class="literal-block">
-first = Word(nums)
-matchExpr = first + &quot;:&quot; + matchPreviousExpr(first)
-</pre>
-<p>will <em>not</em> match the leading &quot;1:1&quot; in &quot;1:10&quot;; the expressions are
-evaluated first, and then compared, so &quot;1&quot; is compared with &quot;10&quot;.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">nestedExpr(opener, closer, content=None, ignoreExpr=quotedString)</tt> - method for defining nested
-lists enclosed in opening and closing delimiters.</p>
-<ul class="simple">
-<li>opener - opening character for a nested list (default=&quot;(&quot;); can also be a pyparsing expression</li>
-<li>closer - closing character for a nested list (default=&quot;)&quot;); can also be a pyparsing expression</li>
-<li>content - expression for items within the nested lists (default=None)</li>
-<li>ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)</li>
-</ul>
-<p>If an expression is not provided for the content argument, the nested
-expression will capture all whitespace-delimited content between delimiters
-as a list of separate values.</p>
-<p>Use the ignoreExpr argument to define expressions that may contain
-opening or closing characters that should not be treated as opening
-or closing characters for nesting, such as quotedString or a comment
-expression.  Specify multiple expressions using an Or or MatchFirst.
-The default is quotedString, but if no expressions are to be ignored,
-then pass None for this argument.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">indentedBlock( statementExpr, indentationStackVar, indent=True)</tt> -
-function to define an indented block of statements, similar to
-indentation-based blocking in Python source code:</p>
-<ul class="simple">
-<li>statementExpr is the expression defining a statement that
-will be found in the indented block; a valid indentedBlock
-must contain at least 1 matching statementExpr</li>
-<li>indentationStackVar is a Python list variable; this variable
-should be common to all <tt class="docutils literal">indentedBlock</tt> expressions defined
-within the same grammar, and should be reinitialized to [1]
-each time the grammar is to be used</li>
-<li>indent is a boolean flag indicating whether the expressions
-within the block must be indented from the current parse
-location; if using indentedBlock to define the left-most
-statements (all starting in column 1), set indent to False</li>
-</ul>
-</li>
-</ul>
-<ul id="originaltextfor">
-<li><p class="first"><tt class="docutils literal">originalTextFor( expr )</tt> - helper function to preserve the originally parsed text, regardless of any
-token processing or conversion done by the contained expression.  For instance, the following expression:</p>
-<pre class="literal-block">
-fullName = Word(alphas) + Word(alphas)
-</pre>
-<p>will return the parse of &quot;John Smith&quot; as ['John', 'Smith'].  In some applications, the actual name as it
-was given in the input string is what is desired.  To do this, use <tt class="docutils literal">originalTextFor</tt>:</p>
-<pre class="literal-block">
-fullName = originalTextFor(Word(alphas) + Word(alphas))
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">ungroup( expr )</tt> - function to &quot;ungroup&quot; returned tokens; useful
-to undo the default behavior of And to always group the returned tokens, even
-if there is only one in the list. (New in 1.5.6)</p>
-</li>
-<li><p class="first"><tt class="docutils literal">lineno( loc, string )</tt> - function to give the line number of the
-location within the string; the first line is line 1, newlines
-start new rows</p>
-</li>
-<li><p class="first"><tt class="docutils literal">col( loc, string )</tt> - function to give the column number of the
-location within the string; the first column is column 1,
-newlines reset the column number to 1</p>
-</li>
-<li><p class="first"><tt class="docutils literal">line( loc, string )</tt> - function to retrieve the line of text
-representing <tt class="docutils literal">lineno( loc, string )</tt>; useful when printing out diagnostic
-messages for exceptions</p>
-</li>
-<li><p class="first"><tt class="docutils literal">srange( rangeSpec )</tt> - function to define a string of characters,
-given a string of the form used by regexp string ranges, such as <tt class="docutils literal"><span class="pre">&quot;[0-9]&quot;</span></tt> for
-all numeric digits, <tt class="docutils literal"><span class="pre">&quot;[A-Z_]&quot;</span></tt> for uppercase characters plus underscore, and
-so on (note that rangeSpec does not include support for generic regular
-expressions, just string range specs)</p>
-</li>
-<li><p class="first"><tt class="docutils literal">getTokensEndLoc()</tt> - function to call from within a parse action to get
-the ending location for the matched tokens</p>
-</li>
-<li><p class="first"><tt class="docutils literal">traceParseAction(fn)</tt> - decorator function to debug parse actions. Lists
-each call, called arguments, and return value or exception</p>
-</li>
-</ul>
-</div>
-<div class="section" id="helper-parse-actions">
-<h2><a class="toc-backref" href="#id16">3.2&nbsp;&nbsp;&nbsp;Helper parse actions</a></h2>
-<ul>
-<li><p class="first"><tt class="docutils literal">removeQuotes</tt> - removes the first and last characters of a quoted string;
-useful to remove the delimiting quotes from quoted strings</p>
-</li>
-<li><p class="first"><tt class="docutils literal">replaceWith(replString)</tt> - returns a parse action that simply returns the
-replString; useful when using transformString, or converting HTML entities, as in:</p>
-<pre class="literal-block">
-nbsp = Literal(&quot;&amp;nbsp;&quot;).setParseAction( replaceWith(&quot;&lt;BLANK&gt;&quot;) )
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">keepOriginalText</tt>- (deprecated, use <a class="reference internal" href="#originaltextfor">originalTextFor</a> instead) restores any internal whitespace or suppressed
-text within the tokens for a matched parse
-expression.  This is especially useful when defining expressions
-for scanString or transformString applications.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">withAttribute( *args, **kwargs )</tt> - helper to create a validating parse action to be used with start tags created
-with <tt class="docutils literal">makeXMLTags</tt> or <tt class="docutils literal">makeHTMLTags</tt>. Use <tt class="docutils literal">withAttribute</tt> to qualify a starting tag
-with a required attribute value, to avoid false matches on common tags such as
-<tt class="docutils literal">&lt;TD&gt;</tt> or <tt class="docutils literal">&lt;DIV&gt;</tt>.</p>
-<p><tt class="docutils literal">withAttribute</tt> can be called with:</p>
-<ul class="simple">
-<li>keyword arguments, as in <tt class="docutils literal"><span class="pre">(class=&quot;Customer&quot;,align=&quot;right&quot;)</span></tt>, or</li>
-<li>a list of name-value tuples, as in <tt class="docutils literal">( (&quot;ns1:class&quot;, <span class="pre">&quot;Customer&quot;),</span> <span class="pre">(&quot;ns2:align&quot;,&quot;right&quot;)</span> )</tt></li>
-</ul>
-<p>An attribute can be specified to have the special value
-<tt class="docutils literal">withAttribute.ANY_VALUE</tt>, which will match any value - use this to
-ensure that an attribute is present but any attribute value is
-acceptable.</p>
-</li>
-<li><p class="first"><tt class="docutils literal">downcaseTokens</tt> - converts all matched tokens to lowercase</p>
-</li>
-<li><p class="first"><tt class="docutils literal">upcaseTokens</tt> - converts all matched tokens to uppercase</p>
-</li>
-<li><p class="first"><tt class="docutils literal">matchOnlyAtCol( columnNumber )</tt> - a parse action that verifies that
-an expression was matched at a particular column, raising a
-ParseException if matching at a different column number; useful when parsing
-tabular data</p>
-</li>
-</ul>
-</div>
-<div class="section" id="common-string-and-token-constants">
-<h2><a class="toc-backref" href="#id17">3.3&nbsp;&nbsp;&nbsp;Common string and token constants</a></h2>
-<ul>
-<li><p class="first"><tt class="docutils literal">alphas</tt> - same as <tt class="docutils literal">string.letters</tt></p>
-</li>
-<li><p class="first"><tt class="docutils literal">nums</tt> - same as <tt class="docutils literal">string.digits</tt></p>
-</li>
-<li><p class="first"><tt class="docutils literal">alphanums</tt> - a string containing <tt class="docutils literal">alphas + nums</tt></p>
-</li>
-<li><p class="first"><tt class="docutils literal">alphas8bit</tt> - a string containing alphabetic 8-bit characters:</p>
-<pre class="literal-block">
-ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ
-</pre>
-</li>
-<li><p class="first"><tt class="docutils literal">printables</tt> - same as <tt class="docutils literal">string.printable</tt>, minus the space (<tt class="docutils literal">' '</tt>) character</p>
-</li>
-<li><p class="first"><tt class="docutils literal">empty</tt> - a global <tt class="docutils literal">Empty()</tt>; will always match</p>
-</li>
-<li><p class="first"><tt class="docutils literal">sglQuotedString</tt> - a string of characters enclosed in 's; may
-include whitespace, but not newlines</p>
-</li>
-<li><p class="first"><tt class="docutils literal">dblQuotedString</tt> - a string of characters enclosed in &quot;s; may
-include whitespace, but not newlines</p>
-</li>
-<li><p class="first"><tt class="docutils literal">quotedString</tt> - <tt class="docutils literal">sglQuotedString | dblQuotedString</tt></p>
-</li>
-<li><p class="first"><tt class="docutils literal">cStyleComment</tt> - a comment block delimited by <tt class="docutils literal"><span class="pre">'/*'</span></tt> and <tt class="docutils literal"><span class="pre">'*/'</span></tt> sequences; can span
-multiple lines, but does not support nesting of comments</p>
-</li>
-<li><p class="first"><tt class="docutils literal">htmlComment</tt> - a comment block delimited by <tt class="docutils literal"><span class="pre">'&lt;!--'</span></tt> and <tt class="docutils literal"><span class="pre">'--&gt;'</span></tt> sequences; can span
-multiple lines, but does not support nesting of comments</p>
-</li>
-<li><p class="first"><tt class="docutils literal">commaSeparatedList</tt> - similar to <tt class="docutils literal">delimitedList</tt>, except that the
-list expressions can be any text value, or a quoted string; quoted strings can
-safely include commas without incorrectly breaking the string into two tokens</p>
-</li>
-<li><p class="first"><tt class="docutils literal">restOfLine</tt> - all remaining printable characters up to but not including the next
-newline</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</body>
-</html>
diff --git a/src/HowToUsePyparsing.txt b/src/HowToUsePyparsing.txt
deleted file mode 100644
--- a/src/HowToUsePyparsing.txt
+++ /dev/null
@@ -1,993 +0,0 @@
-==========================
-Using the pyparsing module
-==========================
-
-:author: Paul McGuire
-:address: ptmcg@users.sourceforge.net
-
-:revision: 1.5.6
-:date: June, 2011
-
-:copyright: Copyright |copy| 2003-2011 Paul McGuire. 
-
-.. |copy| unicode:: 0xA9
-
-:abstract: This document provides how-to instructions for the
-    pyparsing library, an easy-to-use Python module for constructing
-    and executing basic text parsers.  The pyparsing module is useful
-    for evaluating user-definable
-    expressions, processing custom application language commands, or
-    extracting data from formatted reports.
-
-.. sectnum::    :depth: 4
-
-.. contents::   :depth: 4
-
-
-Steps to follow
-===============
-
-To parse an incoming data string, the client code must follow these steps:
-
-1. First define the tokens and patterns to be matched, and assign
-   this to a program variable.  Optional results names or parsing
-   actions can also be defined at this time.
-
-2. Call ``parseString()`` or ``scanString()`` on this variable, passing in 
-   the string to
-   be parsed.  During the matching process, whitespace between
-   tokens is skipped by default (although this can be changed).
-   When token matches occur, any defined parse action methods are
-   called.
-
-3. Process the parsed results, returned as a list of strings.
-   Matching results may also be accessed as named attributes of
-   the returned results, if names are defined in the definition of
-   the token pattern, using ``setResultsName()``.
-
-
-Hello, World!
--------------
-
-The following complete Python program will parse the greeting "Hello, World!",
-or any other greeting of the form "<salutation>, <addressee>!"::
-
-    from pyparsing import Word, alphas
-    
-    greet = Word( alphas ) + "," + Word( alphas ) + "!"
-    greeting = greet.parseString( "Hello, World!" )
-    print greeting
-    
-The parsed tokens are returned in the following form::
-
-    ['Hello', ',', 'World', '!']
-    
-
-Usage notes
------------
-
-- The pyparsing module can be used to interpret simple command
-  strings or algebraic expressions, or can be used to extract data
-  from text reports with complicated format and structure ("screen
-  or report scraping").  However, it is possible that your defined
-  matching patterns may accept invalid inputs.  Use pyparsing to
-  extract data from strings assumed to be well-formatted.  
-
-- To keep up the readability of your code, use operators_  such as ``+``, ``|``, 
-  ``^``, and ``~`` to combine expressions.  You can also combine
-  string literals with ParseExpressions - they will be
-  automatically converted to Literal objects.  For example::
-  
-    integer  = Word( nums )            # simple unsigned integer
-    variable = Word( alphas, max=1 )   # single letter variable, such as x, z, m, etc.
-    arithOp  = Word( "+-*/", max=1 )   # arithmetic operators
-    equation = variable + "=" + integer + arithOp + integer    # will match "x=2+2", etc.
-
-  In the definition of ``equation``, the string ``"="`` will get added as
-  a ``Literal("=")``, but in a more readable way.
-
-- The pyparsing module's default behavior is to ignore whitespace.  This is the
-  case for 99% of all parsers ever written.  This allows you to write simple, clean,
-  grammars, such as the above ``equation``, without having to clutter it up with
-  extraneous ``ws`` markers.  The ``equation`` grammar will successfully parse all of the
-  following statements::
-    
-    x=2+2
-    x = 2+2
-    a = 10   *   4
-    r= 1234/ 100000
-    
-  Of course, it is quite simple to extend this example to support more elaborate expressions, with
-  nesting with parentheses, floating point numbers, scientific notation, and named constants 
-  (such as ``e`` or ``pi``).  See ``fourFn.py``, included in the examples directory.
-
-- To modify pyparsing's default whitespace skipping, you can use one or
-  more of the following methods:
-  
-  - use the static method ``ParserElement.setDefaultWhitespaceChars``
-    to override the normal set of whitespace chars (' \t\n').  For instance
-    when defining a grammar in which newlines are significant, you should
-    call ``ParserElement.setDefaultWhitespaceChars(' \t')`` to remove 
-    newline from the set of skippable whitespace characters.  Calling
-    this method will affect all pyparsing expressions defined afterward.
-    
-  - call ``leaveWhitespace()`` on individual expressions, to suppress the 
-    skipping of whitespace before trying to match the expression
-    
-  - use ``Combine`` to require that successive expressions must be
-    adjacent in the input string.  For instance, this expression::
-    
-      real = Word(nums) + '.' + Word(nums)
-    
-    will match "3.14159", but will also match "3 . 12".  It will also 
-    return the matched results as ['3', '.', '14159'].  By changing this
-    expression to::
-    
-      real = Combine( Word(nums) + '.' + Word(nums) )
-    
-    it will not match numbers with embedded spaces, and it will return a
-    single concatenated string '3.14159' as the parsed token.
-
-- Repetition of expressions can be indicated using the '*' operator.  An
-  expression may be multiplied by an integer value (to indicate an exact
-  repetition count), or by a tuple containing
-  two integers, or None and an integer, representing min and max repetitions
-  (with None representing no min or no max, depending whether it is the first or
-  second tuple element).  See the following examples, where n is used to 
-  indicate an integer value:
-
-  - ``expr*3`` is equivalent to ``expr + expr + expr``
-  
-  - ``expr*(2,3)`` is equivalent to ``expr + expr + Optional(expr)``
-  
-  - ``expr*(n,None)`` or ``expr*(n,)`` is equivalent
-    to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of expr")
-    
-  - ``expr*(None,n)`` is equivalent to ``expr*(0,n)``
-    (read as "0 to n instances of expr")
-    
-  - ``expr*(None,None)`` is equivalent to ``ZeroOrMore(expr)``
-  
-  - ``expr*(1,None)`` is equivalent to ``OneOrMore(expr)``
-
-  Note that ``expr*(None,n)`` does not raise an exception if
-  more than n exprs exist in the input stream; that is,
-  ``expr*(None,n)`` does not enforce a maximum number of expr
-  occurrences.  If this behavior is desired, then write
-  ``expr*(None,n) + ~expr``.
-  
-- ``MatchFirst`` expressions are matched left-to-right, and the first
-  match found will skip all later expressions within, so be sure
-  to define less-specific patterns after more-specific patterns.
-  If you are not sure which expressions are most specific, use Or
-  expressions (defined using the ``^`` operator) - they will always
-  match the longest expression, although they are more
-  compute-intensive.
-  
-- ``Or`` expressions will evaluate all of the specified subexpressions
-  to determine which is the "best" match, that is, which matches
-  the longest string in the input data.  In case of a tie, the
-  left-most expression in the ``Or`` list will win.
-
-- If parsing the contents of an entire file, pass it to the
-  ``parseFile`` method using::
-    
-    expr.parseFile( sourceFile )
-    
-- ``ParseExceptions`` will report the location where an expected token
-  or expression failed to match.  For example, if we tried to use our
-  "Hello, World!" parser to parse "Hello World!" (leaving out the separating
-  comma), we would get an exception, with the message::
-  
-    pyparsing.ParseException: Expected "," (6), (1,7)
-  
-  In the case of complex
-  expressions, the reported location may not be exactly where you
-  would expect.  See more information under ParseException_ .
-
-- Use the ``Group`` class to enclose logical groups of tokens within a
-  sublist.  This will help organize your results into more
-  hierarchical form (the default behavior is to return matching
-  tokens as a flat list of matching input strings).
-  
-- Punctuation may be significant for matching, but is rarely of
-  much interest in the parsed results.  Use the ``suppress()`` method
-  to keep these tokens from cluttering up your returned lists of
-  tokens.  For example, ``delimitedList()`` matches a succession of
-  one or more expressions, separated by delimiters (commas by
-  default), but only returns a list of the actual expressions -
-  the delimiters are used for parsing, but are suppressed from the
-  returned output.
-  
-- Parse actions can be used to convert values from strings to
-  other data types (ints, floats, booleans, etc.).
-  
-- Results names are recommended for retrieving tokens from complex
-  expressions.  It is much easier to access a token using its field
-  name than using a positional index, especially if the expression 
-  contains optional elements.  You can also shortcut
-  the ``setResultsName`` call::
-  
-    stats = "AVE:" + realNum.setResultsName("average") + \
-            "MIN:" + realNum.setResultsName("min") + \
-            "MAX:" + realNum.setResultsName("max")  
-
-  can now be written as this::
-  
-    stats = "AVE:" + realNum("average") + \
-            "MIN:" + realNum("min") + \
-            "MAX:" + realNum("max")  
-  
-- Be careful when defining parse actions that modify global variables or
-  data structures (as in ``fourFn.py``), especially for low level tokens 
-  or expressions that may occur within an ``And`` expression; an early element 
-  of an ``And`` may match, but the overall expression may fail.
-
-- Performance of pyparsing may be slow for complex grammars and/or large
-  input strings.  The psyco_ package can be used to improve the speed of the
-  pyparsing module with no changes to grammar or program logic - observed
-  improvments have been in the 20-50% range.
-
-.. _psyco: http://psyco.sourceforge.net/
-
-
-Classes
-=======
-
-Classes in the pyparsing module
--------------------------------
-
-``ParserElement`` - abstract base class for all pyparsing classes;
-methods for code to use are:
-
-- ``parseString( sourceString, parseAll=False )`` - only called once, on the overall
-  matching pattern; returns a ParseResults_ object that makes the
-  matched tokens available as a list, and optionally as a dictionary, 
-  or as an object with named attributes; if parseAll is set to True, then
-  parseString will raise a ParseException if the grammar does not process
-  the complete input string.
-
-- ``parseFile( sourceFile )`` - a convenience function, that accepts an
-  input file object or filename.  The file contents are passed as a 
-  string to ``parseString()``.  ``parseFile`` also supports the ``parseAll`` argument.
-  
-- ``scanString( sourceString )`` - generator function, used to find and
-  extract matching text in the given source string; for each matched text, 
-  returns a tuple of:
-  
-  - matched tokens (packaged as a ParseResults_ object)
-  
-  - start location of the matched text in the given source string
-  
-  - end location in the given source string
-  
-  ``scanString`` allows you to scan through the input source string for
-  random matches, instead of exhaustively defining the grammar for the entire
-  source text (as would be required with ``parseString``).
-
-- ``transformString( sourceString )`` - convenience wrapper function for
-  ``scanString``, to process the input source string, and replace matching
-  text with the tokens returned from parse actions defined in the grammar
-  (see setParseAction_).
-
-- ``searchString( sourceString )`` - another convenience wrapper function for
-  ``scanString``, returns a list of the matching tokens returned from each
-  call to ``scanString``.
-
-- ``setName( name )`` - associate a short descriptive name for this
-  element, useful in displaying exceptions and trace information
-
-- ``setResultsName( string, listAllMatches=False )`` - name to be given 
-  to tokens matching
-  the element; if multiple tokens within
-  a repetition group (such as ``ZeroOrMore`` or ``delimitedList``) the
-  default is to return only the last matching token - if listAllMatches
-  is set to True, then a list of all the matching tokens is returned. 
-  (New in 1.5.6 - a results name with a trailing '*' character will be
-  interpreted as setting listAllMatches to True.)
-  Note: 
-  ``setResultsName`` returns a *copy* of the element so that a single
-  basic element can be referenced multiple times and given
-  different names within a complex grammar.
-
-.. _setParseAction:
-
-- ``setParseAction( *fn )`` - specify one or more functions to call after successful
-  matching of the element; each function is defined as ``fn( s,
-  loc, toks )``, where:
-  
-  - ``s`` is the original parse string
-  
-  - ``loc`` is the location in the string where matching started
-  
-  - ``toks`` is the list of the matched tokens, packaged as a ParseResults_ object
-  
-  Multiple functions can be attached to a ParserElement by specifying multiple
-  arguments to setParseAction, or by calling setParseAction multiple times.
-  
-  Each parse action function can return a modified ``toks`` list, to perform conversion, or
-  string modifications.  For brevity, ``fn`` may also be a
-  lambda - here is an example of using a parse action to convert matched
-  integer tokens from strings to integers::
-  
-    intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] )
-
-  If ``fn`` does not modify the ``toks`` list, it does not need to return
-  anything at all.
-
-- ``setBreak( breakFlag=True )`` - if breakFlag is True, calls pdb.set_break()
-  as this expression is about to be parsed
-
-- ``copy()`` - returns a copy of a ParserElement; can be used to use the same
-  parse expression in different places in a grammar, with different parse actions
-  attached to each
-
-- ``leaveWhitespace()`` - change default behavior of skipping
-  whitespace before starting matching (mostly used internally to the 
-  pyparsing module, rarely used by client code)
-
-- ``setWhitespaceChars( chars )`` - define the set of chars to be ignored
-  as whitespace before trying to match a specific ParserElement, in place of the
-  default set of whitespace (space, tab, newline, and return)
-
-- ``setDefaultWhitespaceChars( chars )`` - class-level method to override
-  the default set of whitespace chars for all subsequently created ParserElements
-  (including copies); useful when defining grammars that treat one or more of the
-  default whitespace characters as significant (such as a line-sensitive grammar, to 
-  omit newline from the list of ignorable whitespace)
-
-- ``suppress()`` - convenience function to suppress the output of the
-  given element, instead of wrapping it with a Suppress object.
-
-- ``ignore( expr )`` - function to specify parse expression to be
-  ignored while matching defined patterns; can be called
-  repeatedly to specify multiple expressions; useful to specify
-  patterns of comment syntax, for example
-
-- ``setDebug( dbgFlag=True )`` - function to enable/disable tracing output 
-  when trying to match this element
-
-- ``validate()`` - function to verify that the defined grammar does not
-  contain infinitely recursive constructs
-  
-.. _parseWithTabs:
-
-- ``parseWithTabs()`` - function to override default behavior of converting
-  tabs to spaces before parsing the input string; rarely used, except when
-  specifying whitespace-significant grammars using the White_ class.
-
-- ``enablePackrat()`` - a class-level static method to enable a memoizing
-  performance enhancement, known as "packrat parsing".  packrat parsing is 
-  disabled by default, since it may conflict with some user programs that use
-  parse actions.  To activate the packrat feature, your
-  program must call the class method ParserElement.enablePackrat().  If
-  your program uses psyco to "compile as you go", you must call 
-  enablePackrat before calling psyco.full().  If you do not do this,
-  Python will crash.  For best results, call enablePackrat() immediately
-  after importing pyparsing.
-     
-
-Basic ParserElement subclasses
-------------------------------
-
-- ``Literal`` - construct with a string to be matched exactly
-
-- ``CaselessLiteral`` - construct with a string to be matched, but
-  without case checking; results are always returned as the
-  defining literal, NOT as they are found in the input string
-
-- ``Keyword`` - similar to Literal, but must be immediately followed by
-  whitespace, punctuation, or other non-keyword characters; prevents
-  accidental matching of a non-keyword that happens to begin with a
-  defined keyword
-  
-- ``CaselessKeyword`` - similar to Keyword, but with caseless matching
-  behavior
-  
-.. _Word:
-
-- ``Word`` - one or more contiguous characters; construct with a
-  string containing the set of allowed initial characters, and an
-  optional second string of allowed body characters; for instance,
-  a common Word construct is to match a code identifier - in C, a
-  valid identifier must start with an alphabetic character or an 
-  underscore ('_'), followed by a body that can also include numeric
-  digits.  That is, ``a``, ``i``, ``MAX_LENGTH``, ``_a1``, ``b_109_``, and 
-  ``plan9FromOuterSpace``
-  are all valid identifiers; ``9b7z``, ``$a``, ``.section``, and ``0debug``
-  are not.  To
-  define an identifier using a Word, use either of the following::
-  
-  - Word( alphas+"_", alphanums+"_" )
-  - Word( srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]") )
-  
-  If only one
-  string given, it specifies that the same character set defined
-  for the initial character is used for the word body; for instance, to
-  define an identifier that can only be composed of capital letters and
-  underscores, use::
-  
-  - Word( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" )
-  - Word( srange("[A-Z_]") )
-
-  A Word may
-  also be constructed with any of the following optional parameters:
-  
-  - min - indicating a minimum length of matching characters
-  
-  - max - indicating a maximum length of matching characters
-  
-  - exact - indicating an exact length of matching characters
-
-  If exact is specified, it will override any values for min or max.
-  
-  New in 1.5.6 - Sometimes you want to define a word using all 
-  characters in a range except for one or two of them; you can do this
-  with the new excludeChars argument. This is helpful if you want to define
-  a word with all printables except for a single delimiter character, such
-  as '.'. Previously, you would have to create a custom string to pass to Word.
-  With this change, you can just create ``Word(printables, excludeChars='.')``.
-
-- ``CharsNotIn`` - similar to Word_, but matches characters not
-  in the given constructor string (accepts only one string for both
-  initial and body characters); also supports min, max, and exact
-  optional parameters.
-
-- ``Regex`` - a powerful construct, that accepts a regular expression
-  to be matched at the current parse position; accepts an optional
-  flags parameter, corresponding to the flags parameter in the re.compile
-  method; if the expression includes named sub-fields, they will be 
-  represented in the returned ParseResults_
-
-- ``QuotedString`` - supports the definition of custom quoted string
-  formats, in addition to pyparsing's built-in dblQuotedString and
-  sglQuotedString.  QuotedString allows you to specify the following 
-  parameters:
-  
-  - quoteChar - string of one or more characters defining the quote delimiting string
-  
-  - escChar - character to escape quotes, typically backslash (default=None)
-  
-  - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
-  
-  - multiline - boolean indicating whether quotes can span multiple lines (default=False)
-  
-  - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
-  
-  - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
-    
-- ``SkipTo`` - skips ahead in the input string, accepting any
-  characters up to the specified pattern; may be constructed with 
-  the following optional parameters:
-  
-  - include - if set to true, also consumes the match expression
-    (default is false)
-  
-  - ignore - allows the user to specify patterns to not be matched,
-    to prevent false matches
-  
-  - failOn - if a literal string or expression is given for this argument, it defines an expression that
-    should cause the ``SkipTo`` expression to fail, and not skip over that expression
-
-.. _White:
-
-- ``White`` - also similar to Word_, but matches whitespace 
-  characters.  Not usually needed, as whitespace is implicitly
-  ignored by pyparsing.  However, some grammars are whitespace-sensitive,
-  such as those that use leading tabs or spaces to indicating grouping
-  or hierarchy.  (If matching on tab characters, be sure to call 
-  parseWithTabs_ on the top-level parse element.)
-  
-- ``Empty`` - a null expression, requiring no characters - will always
-  match; useful for debugging and for specialized grammars
-  
-- ``NoMatch`` - opposite of Empty, will never match; useful for debugging
-  and for specialized grammars
-
-
-Expression subclasses
----------------------
-
-- ``And`` - construct with a list of ParserElements, all of which must
-  match for And to match; can also be created using the '+'
-  operator; multiple expressions can be Anded together using the '*'
-  operator as in::
-  
-    ipAddress = Word(nums) + ('.'+Word(nums))*3
-    
-  A tuple can be used as the multiplier, indicating a min/max::
-  
-    usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
-
-  A special form of ``And`` is created if the '-' operator is used 
-  instead of the '+' operator.  In the ipAddress example above, if
-  no trailing '.' and Word(nums) are found after matching the initial
-  Word(nums), then pyparsing will back up in the grammar and try other
-  alternatives to ipAddress.  However, if ipAddress is defined as::
-  
-    strictIpAddress = Word(nums) - ('.'+Word(nums))*3
-    
-  then no backing up is done.  If the first Word(nums) of strictIpAddress
-  is matched, then any mismatch after that will raise a ParseSyntaxException,
-  which will halt the parsing process immediately.  By careful use of the
-  '-' operator, grammars can provide meaningful error messages close to 
-  the location where the incoming text does not match the specified
-  grammar.
-
-- ``Or`` - construct with a list of ParserElements, any of which must
-  match for Or to match; if more than one expression matches, the
-  expression that makes the longest match will be used; can also
-  be created using the '^' operator
-
-- ``MatchFirst`` - construct with a list of ParserElements, any of
-  which must match for MatchFirst to match; matching is done
-  left-to-right, taking the first expression that matches; can
-  also be created using the '|' operator
-
-- ``Each`` - similar to And, in that all of the provided expressions
-  must match; however, Each permits matching to be done in any order;
-  can also be created using the '&' operator
-  
-- ``Optional`` - construct with a ParserElement, but this element is
-  not required to match; can be constructed with an optional ``default`` argument,
-  containing a default string or object to be supplied if the given optional
-  parse element is not found in the input string; parse action will only
-  be called if a match is found, or if a default is specified
-
-- ``ZeroOrMore`` - similar to Optional, but can be repeated
-
-- ``OneOrMore`` - similar to ZeroOrMore, but at least one match must
-  be present
-
-- ``FollowedBy`` - a lookahead expression, requires matching of the given
-  expressions, but does not advance the parsing position within the input string
-
-- ``NotAny`` - a negative lookahead expression, prevents matching of named
-  expressions, does not advance the parsing position within the input string; 
-  can also be created using the unary '~' operator
-
-
-.. _operators:
-
-Expression operators
---------------------
-
-- ``~`` - creates NotAny using the expression after the operator
-
-- ``+`` - creates And using the expressions before and after the operator
-
-- ``|`` - creates MatchFirst (first left-to-right match) using the expressions before and after the operator
-
-- ``^`` - creates Or (longest match) using the expressions before and after the operator
-
-- ``&`` - creates Each using the expressions before and after the operator
-
-- ``*`` - creates And by multiplying the expression by the integer operand; if
-  expression is multiplied by a 2-tuple, creates an And of (min,max)
-  expressions (similar to "{min,max}" form in regular expressions); if
-  min is None, intepret as (0,max); if max is None, interpret as 
-  expr*min + ZeroOrMore(expr)
-    
-- ``-`` - like ``+`` but with no backup and retry of alternatives
-
-- ``*`` - repetition of expression
-
-- ``==`` - matching expression to string; returns True if the string matches the given expression
-
-- ``<<`` - inserts the expression following the operator as the body of the 
-  Forward expression before the operator
-
-
-
-Positional subclasses
----------------------
-
-- ``StringStart`` - matches beginning of the text
-
-- ``StringEnd`` - matches the end of the text
-
-- ``LineStart`` - matches beginning of a line (lines delimited by ``\n`` characters)
-
-- ``LineEnd`` - matches the end of a line
-
-- ``WordStart`` - matches a leading word boundary
-
-- ``WordEnd`` - matches a trailing word boundary
-
-
-
-Converter subclasses
---------------------
-
-- ``Upcase`` - converts matched tokens to uppercase (deprecated -
-  use ``upcaseTokens`` parse action instead)
-
-- ``Combine`` - joins all matched tokens into a single string, using
-  specified joinString (default ``joinString=""``); expects
-  all matching tokens to be adjacent, with no intervening
-  whitespace (can be overridden by specifying ``adjacent=False`` in constructor)
-
-- ``Suppress`` - clears matched tokens; useful to keep returned
-  results from being cluttered with required but uninteresting
-  tokens (such as list delimiters)
-
-
-Special subclasses
-------------------
-
-- ``Group`` - causes the matched tokens to be enclosed in a list;
-  useful in repeated elements like ``ZeroOrMore`` and ``OneOrMore`` to
-  break up matched tokens into groups for each repeated pattern
-
-- ``Dict`` - like ``Group``, but also constructs a dictionary, using the
-  [0]'th elements of all enclosed token lists as the keys, and
-  each token list as the value
-
-- ``SkipTo`` - catch-all matching expression that accepts all characters
-  up until the given pattern is found to match; useful for specifying
-  incomplete grammars
-
-- ``Forward`` - placeholder token used to define recursive token
-  patterns; when defining the actual expression later in the
-  program, insert it into the ``Forward`` object using the ``<<``
-  operator (see ``fourFn.py`` for an example).
-
-
-Other classes
--------------
-.. _ParseResults:
-
-- ``ParseResults`` - class used to contain and manage the lists of tokens
-  created from parsing the input using the user-defined parse 
-  expression.  ParseResults can be accessed in a number of ways:
-
-  - as a list
-  
-    - total list of elements can be found using len()
-    
-    - individual elements can be found using [0], [1], [-1], etc.
-    
-    - elements can be deleted using ``del``
-    
-    - the -1th element can be extracted and removed in a single operation
-      using ``pop()``, or any element can be extracted and removed 
-      using ``pop(n)``
-    
-  - as a dictionary
-  
-    - if ``setResultsName()`` is used to name elements within the 
-      overall parse expression, then these fields can be referenced
-      as dictionary elements or as attributes
-      
-    - the Dict class generates dictionary entries using the data of the
-      input text - in addition to ParseResults listed as ``[ [ a1, b1, c1, ...], [ a2, b2, c2, ...]  ]``
-      it also acts as a dictionary with entries defined as ``{ a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }``; 
-      this is especially useful when processing tabular data where the first column contains a key 
-      value for that line of data
-      
-    - list elements that are deleted using ``del`` will still be accessible by their
-      dictionary keys
-      
-    - supports ``get()``, ``items()`` and ``keys()`` methods, similar to a dictionary
-    
-    - a keyed item can be extracted and removed using ``pop(key)``.  Here
-      key must be non-numeric (such as a string), in order to use dict 
-      extraction instead of list extraction.
-      
-    - new named elements can be added (in a parse action, for instance), using the same
-      syntax as adding an item to a dict (``parseResults["X"]="new item"``); named elements can be removed using ``del parseResults["X"]``
-      
-  - as a nested list
-  
-    - results returned from the Group class are encapsulated within their
-      own list structure, so that the tokens can be handled as a hierarchical
-      tree
-      
-  ParseResults can also be converted to an ordinary list of strings
-  by calling ``asList()``.  Note that this will strip the results of any
-  field names that have been defined for any embedded parse elements.
-  (The ``pprint`` module is especially good at printing out the nested contents
-  given by ``asList()``.)
-  
-  Finally, ParseResults can be converted to an XML string by calling ``asXML()``. Where
-  possible, results will be tagged using the results names defined for the respective
-  ParseExpressions.  ``asXML()`` takes two optional arguments:
-  
-  - doctagname - for ParseResults that do not have a defined name, this argument
-    will wrap the resulting XML in a set of opening and closing tags ``<doctagname>``
-    and ``</doctagname>``.
-
-  - namedItemsOnly (default=False) - flag to indicate if the generated XML should 
-    skip items that do not have defined names.  If a nested group item is named, then all
-    embedded items will be included, whether they have names or not.
-
-
-Exception classes and Troubleshooting
--------------------------------------
-
-.. _ParseException:
-
-- ``ParseException`` - exception returned when a grammar parse fails;
-  ParseExceptions have attributes loc, msg, line, lineno, and column; to view the 
-  text line and location where the reported ParseException occurs, use::
-  
-    except ParseException, err:
-        print err.line
-        print " "*(err.column-1) + "^"
-        print err
-  
-- ``RecursiveGrammarException`` - exception returned by ``validate()`` if
-  the grammar contains a recursive infinite loop, such as::
-  
-    badGrammar = Forward()
-    goodToken = Literal("A")
-    badGrammar << Optional(goodToken) + badGrammar
-
-- ``ParseFatalException`` - exception that parse actions can raise to stop parsing
-  immediately.  Should be used when a semantic error is found in the input text, such
-  as a mismatched XML tag.
-
-- ``ParseSyntaxException`` - subclass of ``ParseFatalException`` raised when a
-  syntax error is found, based on the use of the '-' operator when defining
-  a sequence of expressions in an ``And`` expression.
-
-You can also get some insights into the parsing logic using diagnostic parse actions,
-and setDebug(), or test the matching of expression fragments by testing them using 
-scanString().
-
-
-Miscellaneous attributes and methods
-====================================
-
-Helper methods
---------------
-
-- ``delimitedList( expr, delim=',')`` - convenience function for
-  matching one or more occurrences of expr, separated by delim.
-  By default, the delimiters are suppressed, so the returned results contain
-  only the separate list elements.  Can optionally specify ``combine=True``,
-  indicating that the expressions and delimiters should be returned as one
-  combined value (useful for scoped variables, such as "a.b.c", or 
-  "a::b::c", or paths such as "a/b/c").
-
-- ``countedArray( expr )`` - convenience function for a pattern where an list of
-  instances of the given expression are preceded by an integer giving the count of
-  elements in the list.  Returns an expression that parses the leading integer,
-  reads exactly that many expressions, and returns the array of expressions in the
-  parse results - the leading integer is suppressed from the results (although it
-  is easily reconstructed by using len on the returned array).
-
-- ``oneOf( string, caseless=False )`` - convenience function for quickly declaring an
-  alternative set of ``Literal`` tokens, by splitting the given string on 
-  whitespace boundaries.  The tokens are sorted so that longer
-  matches are attempted first; this ensures that a short token does
-  not mask a longer one that starts with the same characters. If ``caseless=True``, 
-  will create an alternative set of CaselessLiteral tokens.
-
-- ``dictOf( key, value )`` - convenience function for quickly declaring a 
-  dictionary pattern of ``Dict( ZeroOrMore( Group( key + value ) ) )``.
-
-- ``makeHTMLTags( tagName )`` and ``makeXMLTags( tagName )`` - convenience
-  functions to create definitions of opening and closing tag expressions.  Returns
-  a pair of expressions, for the corresponding <tag> and </tag> strings.  Includes
-  support for attributes in the opening tag, such as <tag attr1="abc"> - attributes
-  are returned as keyed tokens in the returned ParseResults.  ``makeHTMLTags`` is less
-  restrictive than ``makeXMLTags``, especially with respect to case sensitivity.
-
-- ``operatorPrecedence(baseOperand, operatorList)`` - convenience function to define a 
-  grammar for parsing
-  expressions with a hierarchical precedence of operators. To use the operatorPrecedence 
-  helper:
-  
-  1.  Define the base "atom" operand term of the grammar.
-      For this simple grammar, the smallest operand is either
-      and integer or a variable.  This will be the first argument
-      to the operatorPrecedence method.
-      
-  2.  Define a list of tuples for each level of operator
-      precendence.  Each tuple is of the form
-      ``(opExpr, numTerms, rightLeftAssoc, parseAction)``, where:
-      
-      - opExpr is the pyparsing expression for the operator;
-        may also be a string, which will be converted to a Literal; if
-        None, indicates an empty operator, such as the implied
-        multiplication operation between 'm' and 'x' in "y = mx + b".
-      
-      - numTerms is the number of terms for this operator (must
-        be 1 or 2)
-      
-      - rightLeftAssoc is the indicator whether the operator is
-        right or left associative, using the pyparsing-defined
-        constants ``opAssoc.RIGHT`` and ``opAssoc.LEFT``.
-      
-      - parseAction is the parse action to be associated with 
-        expressions matching this operator expression (the
-        parse action tuple member may be omitted)
-        
-  3.  Call operatorPrecedence passing the operand expression and
-      the operator precedence list, and save the returned value
-      as the generated pyparsing expression.  You can then use
-      this expression to parse input strings, or incorporate it
-      into a larger, more complex grammar.
- 
-- ``matchPreviousLiteral`` and ``matchPreviousExpr`` - function to define and 
-  expression that matches the same content
-  as was parsed in a previous parse expression.  For instance::
-  
-        first = Word(nums)
-        matchExpr = first + ":" + matchPreviousLiteral(first)
-  
-  will match "1:1", but not "1:2".  Since this matches at the literal
-  level, this will also match the leading "1:1" in "1:10".
-  
-  In contrast::
-  
-        first = Word(nums)
-        matchExpr = first + ":" + matchPreviousExpr(first)
-           
-  will *not* match the leading "1:1" in "1:10"; the expressions are
-  evaluated first, and then compared, so "1" is compared with "10".
-
-- ``nestedExpr(opener, closer, content=None, ignoreExpr=quotedString)`` - method for defining nested 
-  lists enclosed in opening and closing delimiters.
-
-  - opener - opening character for a nested list (default="("); can also be a pyparsing expression
-    
-  - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
-    
-  - content - expression for items within the nested lists (default=None)
-    
-  - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
-
-  If an expression is not provided for the content argument, the nested
-  expression will capture all whitespace-delimited content between delimiters
-  as a list of separate values.
-
-  Use the ignoreExpr argument to define expressions that may contain
-  opening or closing characters that should not be treated as opening
-  or closing characters for nesting, such as quotedString or a comment
-  expression.  Specify multiple expressions using an Or or MatchFirst.
-  The default is quotedString, but if no expressions are to be ignored,
-  then pass None for this argument.
-
-
-- ``indentedBlock( statementExpr, indentationStackVar, indent=True)`` -
-  function to define an indented block of statements, similar to 
-  indentation-based blocking in Python source code:
-  
-  - statementExpr is the expression defining a statement that
-    will be found in the indented block; a valid indentedBlock
-    must contain at least 1 matching statementExpr
-       
-  - indentationStackVar is a Python list variable; this variable
-    should be common to all ``indentedBlock`` expressions defined
-    within the same grammar, and should be reinitialized to [1]
-    each time the grammar is to be used
-        
-  - indent is a boolean flag indicating whether the expressions
-    within the block must be indented from the current parse
-    location; if using indentedBlock to define the left-most
-    statements (all starting in column 1), set indent to False
-
-.. _originalTextFor:
-
-- ``originalTextFor( expr )`` - helper function to preserve the originally parsed text, regardless of any
-  token processing or conversion done by the contained expression.  For instance, the following expression::
-  
-        fullName = Word(alphas) + Word(alphas)
-
-  will return the parse of "John Smith" as ['John', 'Smith'].  In some applications, the actual name as it
-  was given in the input string is what is desired.  To do this, use ``originalTextFor``::
-  
-        fullName = originalTextFor(Word(alphas) + Word(alphas))
-
-- ``ungroup( expr )`` - function to "ungroup" returned tokens; useful
-  to undo the default behavior of And to always group the returned tokens, even
-  if there is only one in the list. (New in 1.5.6)
-
-- ``lineno( loc, string )`` - function to give the line number of the
-  location within the string; the first line is line 1, newlines
-  start new rows
-
-- ``col( loc, string )`` - function to give the column number of the
-  location within the string; the first column is column 1,
-  newlines reset the column number to 1
-
-- ``line( loc, string )`` - function to retrieve the line of text
-  representing ``lineno( loc, string )``; useful when printing out diagnostic
-  messages for exceptions
-
-- ``srange( rangeSpec )`` - function to define a string of characters, 
-  given a string of the form used by regexp string ranges, such as ``"[0-9]"`` for 
-  all numeric digits, ``"[A-Z_]"`` for uppercase characters plus underscore, and 
-  so on (note that rangeSpec does not include support for generic regular 
-  expressions, just string range specs)
-
-- ``getTokensEndLoc()`` - function to call from within a parse action to get
-  the ending location for the matched tokens
-  
-- ``traceParseAction(fn)`` - decorator function to debug parse actions. Lists
-  each call, called arguments, and return value or exception
-  
-  
-
-Helper parse actions
---------------------
-
-- ``removeQuotes`` - removes the first and last characters of a quoted string;
-  useful to remove the delimiting quotes from quoted strings
-  
-- ``replaceWith(replString)`` - returns a parse action that simply returns the
-  replString; useful when using transformString, or converting HTML entities, as in::
-  
-      nbsp = Literal("&nbsp;").setParseAction( replaceWith("<BLANK>") )
-
-- ``keepOriginalText``- (deprecated, use originalTextFor_ instead) restores any internal whitespace or suppressed 
-  text within the tokens for a matched parse
-  expression.  This is especially useful when defining expressions
-  for scanString or transformString applications.
-
-- ``withAttribute( *args, **kwargs )`` - helper to create a validating parse action to be used with start tags created 
-  with ``makeXMLTags`` or ``makeHTMLTags``. Use ``withAttribute`` to qualify a starting tag 
-  with a required attribute value, to avoid false matches on common tags such as 
-  ``<TD>`` or ``<DIV>``.
-  
-  ``withAttribute`` can be called with:
-  
-  - keyword arguments, as in ``(class="Customer",align="right")``, or
-  
-  - a list of name-value tuples, as in ``( ("ns1:class", "Customer"), ("ns2:align","right") )``
-
-  An attribute can be specified to have the special value 
-  ``withAttribute.ANY_VALUE``, which will match any value - use this to 
-  ensure that an attribute is present but any attribute value is
-  acceptable.
-
-- ``downcaseTokens`` - converts all matched tokens to lowercase
-
-- ``upcaseTokens`` - converts all matched tokens to uppercase
-
-- ``matchOnlyAtCol( columnNumber )`` - a parse action that verifies that
-  an expression was matched at a particular column, raising a 
-  ParseException if matching at a different column number; useful when parsing
-  tabular data
-
-
-
-Common string and token constants
----------------------------------
-
-- ``alphas`` - same as ``string.letters``
-
-- ``nums`` - same as ``string.digits``
-
-- ``alphanums`` - a string containing ``alphas + nums``
-
-- ``alphas8bit`` - a string containing alphabetic 8-bit characters::
-
-    �������������������������������������������������������������
-
-- ``printables`` - same as ``string.printable``, minus the space (``' '``) character
-
-- ``empty`` - a global ``Empty()``; will always match
-
-- ``sglQuotedString`` - a string of characters enclosed in 's; may
-  include whitespace, but not newlines
-
-- ``dblQuotedString`` - a string of characters enclosed in "s; may
-  include whitespace, but not newlines
-
-- ``quotedString`` - ``sglQuotedString | dblQuotedString``
-
-- ``cStyleComment`` - a comment block delimited by ``'/*'`` and ``'*/'`` sequences; can span
-  multiple lines, but does not support nesting of comments
-
-- ``htmlComment`` - a comment block delimited by ``'<!--'`` and ``'-->'`` sequences; can span
-  multiple lines, but does not support nesting of comments
-
-- ``commaSeparatedList`` - similar to ``delimitedList``, except that the
-  list expressions can be any text value, or a quoted string; quoted strings can
-  safely include commas without incorrectly breaking the string into two tokens
-
-- ``restOfLine`` - all remaining printable characters up to but not including the next
-  newline
diff --git a/src/LICENSE b/src/LICENSE
deleted file mode 100644
--- a/src/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/MANIFEST.in b/src/MANIFEST.in
deleted file mode 100644
--- a/src/MANIFEST.in
+++ /dev/null
@@ -1,7 +0,0 @@
-include pyparsing.py
-include HowToUsePyparsing.html pyparsingClassDiagram.*
-include README CHANGES LICENSE
-include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html
-include htmldoc/*.*
-include docs/*.*
-include robots.txt
diff --git a/src/MANIFEST.in_bdist b/src/MANIFEST.in_bdist
deleted file mode 100644
--- a/src/MANIFEST.in_bdist
+++ /dev/null
@@ -1,7 +0,0 @@
-include pyparsing.py
-include HowToUsePyparsing.html pyparsingClassDiagram.*
-include README CHANGES LICENSE
-include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html
-include htmldoc/*.*
-include docs/*.*
-include robots.txt
diff --git a/src/MANIFEST.in_src b/src/MANIFEST.in_src
deleted file mode 100644
--- a/src/MANIFEST.in_src
+++ /dev/null
@@ -1,7 +0,0 @@
-include pyparsing_py2.py pyparsing_py3.py
-include HowToUsePyparsing.html pyparsingClassDiagram.*
-include README CHANGES LICENSE
-include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html
-include htmldoc/*.*
-include docs/*.*
-include robots.txt
diff --git a/src/README b/src/README
deleted file mode 100644
--- a/src/README
+++ /dev/null
@@ -1,72 +0,0 @@
-====================================
-PyParsing -- A Python Parsing Module
-====================================
-
-Introduction
-============
-
-The pyparsing module is an alternative approach to creating and executing 
-simple grammars, vs. the traditional lex/yacc approach, or the use of 
-regular expressions.  The pyparsing module provides a library of classes 
-that client code uses to construct the grammar directly in Python code.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form 
-"<salutation>, <addressee>!"):
-
-    from pyparsing import Word, alphas
-    greet = Word( alphas ) + "," + Word( alphas ) + "!"
-    hello = "Hello, World!"
-    print hello, "->", greet.parseString( hello )
-
-The program outputs the following:
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the 
-self-explanatory class names, and the use of '+', '|' and '^' operator 
-definitions.
-
-The parsed results returned from parseString() can be accessed as a 
-nested list, a dictionary, or an object with named attributes.
-
-The pyparsing module handles some of the problems that are typically 
-vexing when writing text parsers:
-- extra or missing whitespace (the above program will also handle 
-  "Hello,World!", "Hello  ,  World  !", etc.)
-- quoted strings
-- embedded comments
-
-The .zip file includes examples of a simple SQL parser, simple CORBA IDL 
-parser, a config file parser, a chemical formula parser, and a four-
-function algebraic notation parser.  It also includes a simple how-to 
-document, and a UML class diagram of the library's classes.
-
-
-
-Installation
-============
-
-Do the usual:
-
-    python setup.py install
-    
-(pyparsing requires Python 2.3.2 or later.)
-
-
-Documentation
-=============
-
-See:
-
-    HowToUsePyparsing.html
-
-
-License
-=======
-
-    MIT License. See header of pyparsing.py
-
-History
-=======
-
-    See CHANGES file.
diff --git a/src/genEpydoc.bat b/src/genEpydoc.bat
deleted file mode 100644
--- a/src/genEpydoc.bat
+++ /dev/null
@@ -1,1 +0,0 @@
-python c:\python26\scripts\epydoc -v --name pyparsing -o htmldoc --inheritance listed --no-private pyparsing.py
diff --git a/src/makeRelease.bat b/src/makeRelease.bat
deleted file mode 100644
--- a/src/makeRelease.bat
+++ /dev/null
@@ -1,25 +0,0 @@
-set MAKING_PYPARSING_RELEASE=1
-
-if exist pyparsing.py del pyparsing.py
-rmdir build
-rmdir dist
-
-copy/y MANIFEST.in_src MANIFEST.in
-if exist MANIFEST del MANIFEST
-python setup.py sdist --formats=gztar,zip
-
-copy/y MANIFEST.in_bdist MANIFEST.in
-if exist MANIFEST del MANIFEST
-
-copy/y pyparsing_py2.py pyparsing.py
-python setup.py bdist_wininst --target-version=2.4
-python setup.py bdist_wininst --target-version=2.5
-python setup.py bdist_wininst --target-version=2.6
-python setup.py bdist_wininst --target-version=2.7
-
-copy/y pyparsing_py3.py pyparsing.py
-python setup.py bdist_wininst --target-version=3.0
-python setup.py bdist_wininst --target-version=3.1
-python setup.py bdist_wininst --target-version=3.2
-
-set MAKING_PYPARSING_RELEASE=
\ No newline at end of file
diff --git a/src/pyparsing.py b/src/pyparsing.py
deleted file mode 100644
--- a/src/pyparsing.py
+++ /dev/null
@@ -1,3740 +0,0 @@
-# module pyparsing.py
-#
-# Copyright (c) 2003-2011  Paul T. McGuire
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-#from __future__ import generators
-
-__doc__ = \
-"""
-pyparsing module - Classes and methods to define and execute parsing grammars
-
-The pyparsing module is an alternative approach to creating and executing simple grammars,
-vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
-don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
-provides a library of classes that you use to construct the grammar directly in Python.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form C{"<salutation>, <addressee>!"})::
-
-    from pyparsing import Word, alphas
-
-    # define grammar of a greeting
-    greet = Word( alphas ) + "," + Word( alphas ) + "!"
-
-    hello = "Hello, World!"
-    print hello, "->", greet.parseString( hello )
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the self-explanatory
-class names, and the use of '+', '|' and '^' operators.
-
-The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an
-object with named attributes.
-
-The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
- - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
- - quoted strings
- - embedded comments
-"""
-
-__version__ = "1.5.7"
-__versionTime__ = "3 August 2012 05:00"
-__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
-
-import string
-from weakref import ref as wkref
-import copy
-import sys
-import warnings
-import re
-import sre_constants
-#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
-
-__all__ = [
-'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
-'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
-'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
-'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
-'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
-'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
-'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
-'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
-'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
-'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
-'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
-'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
-'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
-'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
-'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
-'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
-'indentedBlock', 'originalTextFor', 'ungroup',
-]
-
-"""
-Detect if we are running version 3.X and make appropriate changes
-Robert A. Clark
-"""
-_PY3K = sys.version_info[0] > 2
-if _PY3K:
-    _MAX_INT = sys.maxsize
-    basestring = str
-    unichr = chr
-    _ustr = str
-else:
-    _MAX_INT = sys.maxint
-    range = xrange
-    set = lambda s : dict( [(c,0) for c in s] )
-
-    def _ustr(obj):
-        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
-           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
-           then < returns the unicode object | encodes it with the default encoding | ... >.
-        """
-        if isinstance(obj,unicode):
-            return obj
-
-        try:
-            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
-            # it won't break any existing code.
-            return str(obj)
-
-        except UnicodeEncodeError:
-            # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
-            # state that "The return value must be a string object". However, does a
-            # unicode object (being a subclass of basestring) count as a "string
-            # object"?
-            # If so, then return a unicode object:
-            return unicode(obj)
-            # Else encode it... but how? There are many choices... :)
-            # Replace unprintables with escape codes?
-            #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
-            # Replace unprintables with question marks?
-            #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
-            # ...
-
-# build list of single arg builtins, tolerant of Python version, that can be used as parse actions
-singleArgBuiltins = []
-import __builtin__
-for fname in "sum len sorted reversed list tuple set any all min max".split():
-    try:
-        singleArgBuiltins.append(getattr(__builtin__,fname))
-    except AttributeError:
-        continue
-
-def _xml_escape(data):
-    """Escape &, <, >, ", ', etc. in a string of data."""
-
-    # ampersand must be replaced first
-    from_symbols = '&><"\''
-    to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
-    for from_,to_ in zip(from_symbols, to_symbols):
-        data = data.replace(from_, to_)
-    return data
-
-class _Constants(object):
-    pass
-
-alphas     = string.ascii_lowercase + string.ascii_uppercase
-nums       = "0123456789"
-hexnums    = nums + "ABCDEFabcdef"
-alphanums  = alphas + nums
-_bslash    = chr(92)
-printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
-
-class ParseBaseException(Exception):
-    """base exception class for all parsing runtime exceptions"""
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, pstr, loc=0, msg=None, elem=None ):
-        self.loc = loc
-        if msg is None:
-            self.msg = pstr
-            self.pstr = ""
-        else:
-            self.msg = msg
-            self.pstr = pstr
-        self.parserElement = elem
-
-    def __getattr__( self, aname ):
-        """supported attributes by name are:
-            - lineno - returns the line number of the exception text
-            - col - returns the column number of the exception text
-            - line - returns the line containing the exception text
-        """
-        if( aname == "lineno" ):
-            return lineno( self.loc, self.pstr )
-        elif( aname in ("col", "column") ):
-            return col( self.loc, self.pstr )
-        elif( aname == "line" ):
-            return line( self.loc, self.pstr )
-        else:
-            raise AttributeError(aname)
-
-    def __str__( self ):
-        return "%s (at char %d), (line:%d, col:%d)" % \
-                ( self.msg, self.loc, self.lineno, self.column )
-    def __repr__( self ):
-        return _ustr(self)
-    def markInputline( self, markerString = ">!<" ):
-        """Extracts the exception line from the input string, and marks
-           the location of the exception with a special symbol.
-        """
-        line_str = self.line
-        line_column = self.column - 1
-        if markerString:
-            line_str = "".join( [line_str[:line_column],
-                                markerString, line_str[line_column:]])
-        return line_str.strip()
-    def __dir__(self):
-        return "loc msg pstr parserElement lineno col line " \
-               "markInputline __str__ __repr__".split()
-
-class ParseException(ParseBaseException):
-    """exception thrown when parse expressions don't match class;
-       supported attributes by name are:
-        - lineno - returns the line number of the exception text
-        - col - returns the column number of the exception text
-        - line - returns the line containing the exception text
-    """
-    pass
-
-class ParseFatalException(ParseBaseException):
-    """user-throwable exception thrown when inconsistent parse content
-       is found; stops all parsing immediately"""
-    pass
-
-class ParseSyntaxException(ParseFatalException):
-    """just like C{L{ParseFatalException}}, but thrown internally when an
-       C{L{ErrorStop<And._ErrorStop>}} ('-' operator) indicates that parsing is to stop immediately because
-       an unbacktrackable syntax error has been found"""
-    def __init__(self, pe):
-        super(ParseSyntaxException, self).__init__(
-                                    pe.pstr, pe.loc, pe.msg, pe.parserElement)
-
-#~ class ReparseException(ParseBaseException):
-    #~ """Experimental class - parse actions can raise this exception to cause
-       #~ pyparsing to reparse the input string:
-        #~ - with a modified input string, and/or
-        #~ - with a modified start location
-       #~ Set the values of the ReparseException in the constructor, and raise the
-       #~ exception in a parse action to cause pyparsing to use the new string/location.
-       #~ Setting the values as None causes no change to be made.
-       #~ """
-    #~ def __init_( self, newstring, restartLoc ):
-        #~ self.newParseText = newstring
-        #~ self.reparseLoc = restartLoc
-
-class RecursiveGrammarException(Exception):
-    """exception thrown by C{validate()} if the grammar could be improperly recursive"""
-    def __init__( self, parseElementList ):
-        self.parseElementTrace = parseElementList
-
-    def __str__( self ):
-        return "RecursiveGrammarException: %s" % self.parseElementTrace
-
-class _ParseResultsWithOffset(object):
-    def __init__(self,p1,p2):
-        self.tup = (p1,p2)
-    def __getitem__(self,i):
-        return self.tup[i]
-    def __repr__(self):
-        return repr(self.tup)
-    def setOffset(self,i):
-        self.tup = (self.tup[0],i)
-
-class ParseResults(object):
-    """Structured parse results, to provide multiple means of access to the parsed data:
-       - as a list (C{len(results)})
-       - by list index (C{results[0], results[1]}, etc.)
-       - by attribute (C{results.<resultsName>})
-       """
-    #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
-    def __new__(cls, toklist, name=None, asList=True, modal=True ):
-        if isinstance(toklist, cls):
-            return toklist
-        retobj = object.__new__(cls)
-        retobj.__doinit = True
-        return retobj
-
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, toklist, name=None, asList=True, modal=True, isinstance=isinstance ):
-        if self.__doinit:
-            self.__doinit = False
-            self.__name = None
-            self.__parent = None
-            self.__accumNames = {}
-            if isinstance(toklist, list):
-                self.__toklist = toklist[:]
-            else:
-                self.__toklist = [toklist]
-            self.__tokdict = dict()
-
-        if name is not None and name:
-            if not modal:
-                self.__accumNames[name] = 0
-            if isinstance(name,int):
-                name = _ustr(name) # will always return a str, but use _ustr for consistency
-            self.__name = name
-            if not toklist in (None,'',[]):
-                if isinstance(toklist,basestring):
-                    toklist = [ toklist ]
-                if asList:
-                    if isinstance(toklist,ParseResults):
-                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
-                    else:
-                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
-                    self[name].__name = name
-                else:
-                    try:
-                        self[name] = toklist[0]
-                    except (KeyError,TypeError,IndexError):
-                        self[name] = toklist
-
-    def __getitem__( self, i ):
-        if isinstance( i, (int,slice) ):
-            return self.__toklist[i]
-        else:
-            if i not in self.__accumNames:
-                return self.__tokdict[i][-1][0]
-            else:
-                return ParseResults([ v[0] for v in self.__tokdict[i] ])
-
-    def __setitem__( self, k, v, isinstance=isinstance ):
-        if isinstance(v,_ParseResultsWithOffset):
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
-            sub = v[0]
-        elif isinstance(k,int):
-            self.__toklist[k] = v
-            sub = v
-        else:
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
-            sub = v
-        if isinstance(sub,ParseResults):
-            sub.__parent = wkref(self)
-
-    def __delitem__( self, i ):
-        if isinstance(i,(int,slice)):
-            mylen = len( self.__toklist )
-            del self.__toklist[i]
-
-            # convert int to slice
-            if isinstance(i, int):
-                if i < 0:
-                    i += mylen
-                i = slice(i, i+1)
-            # get removed indices
-            removed = list(range(*i.indices(mylen)))
-            removed.reverse()
-            # fixup indices in token dictionary
-            for name in self.__tokdict:
-                occurrences = self.__tokdict[name]
-                for j in removed:
-                    for k, (value, position) in enumerate(occurrences):
-                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
-        else:
-            del self.__tokdict[i]
-
-    def __contains__( self, k ):
-        return k in self.__tokdict
-
-    def __len__( self ): return len( self.__toklist )
-    def __bool__(self): return len( self.__toklist ) > 0
-    __nonzero__ = __bool__
-    def __iter__( self ): return iter( self.__toklist )
-    def __reversed__( self ): return iter( self.__toklist[::-1] )
-    def keys( self ):
-        """Returns all named result keys."""
-        return self.__tokdict.keys()
-
-    def pop( self, index=-1 ):
-        """Removes and returns item at specified index (default=last).
-           Will work with either numeric indices or dict-key indicies."""
-        ret = self[index]
-        del self[index]
-        return ret
-
-    def get(self, key, defaultValue=None):
-        """Returns named result matching the given key, or if there is no
-           such name, then returns the given C{defaultValue} or C{None} if no
-           C{defaultValue} is specified."""
-        if key in self:
-            return self[key]
-        else:
-            return defaultValue
-
-    def insert( self, index, insStr ):
-        """Inserts new element at location index in the list of parsed tokens."""
-        self.__toklist.insert(index, insStr)
-        # fixup indices in token dictionary
-        for name in self.__tokdict:
-            occurrences = self.__tokdict[name]
-            for k, (value, position) in enumerate(occurrences):
-                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
-
-    def items( self ):
-        """Returns all named result keys and values as a list of tuples."""
-        return [(k,self[k]) for k in self.__tokdict]
-
-    def values( self ):
-        """Returns all named result values."""
-        return [ v[-1][0] for v in self.__tokdict.values() ]
-
-    def __getattr__( self, name ):
-        if True: #name not in self.__slots__:
-            if name in self.__tokdict:
-                if name not in self.__accumNames:
-                    return self.__tokdict[name][-1][0]
-                else:
-                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
-            else:
-                return ""
-        return None
-
-    def __add__( self, other ):
-        ret = self.copy()
-        ret += other
-        return ret
-
-    def __iadd__( self, other ):
-        if other.__tokdict:
-            offset = len(self.__toklist)
-            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
-            otheritems = other.__tokdict.items()
-            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
-                                for (k,vlist) in otheritems for v in vlist]
-            for k,v in otherdictitems:
-                self[k] = v
-                if isinstance(v[0],ParseResults):
-                    v[0].__parent = wkref(self)
-            
-        self.__toklist += other.__toklist
-        self.__accumNames.update( other.__accumNames )
-        return self
-
-    def __radd__(self, other):
-        if isinstance(other,int) and other == 0:
-            return self.copy()
-        
-    def __repr__( self ):
-        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
-
-    def __str__( self ):
-        out = []
-        for i in self.__toklist:
-            if isinstance(i, ParseResults):
-                out.append(_ustr(i))
-            else:
-                out.append(repr(i))
-        return '[' + ', '.join(out) + ']'
-
-    def _asStringList( self, sep='' ):
-        out = []
-        for item in self.__toklist:
-            if out and sep:
-                out.append(sep)
-            if isinstance( item, ParseResults ):
-                out += item._asStringList()
-            else:
-                out.append( _ustr(item) )
-        return out
-
-    def asList( self ):
-        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
-        out = []
-        for res in self.__toklist:
-            if isinstance(res,ParseResults):
-                out.append( res.asList() )
-            else:
-                out.append( res )
-        return out
-
-    def asDict( self ):
-        """Returns the named parse results as dictionary."""
-        return dict( self.items() )
-
-    def copy( self ):
-        """Returns a new copy of a C{ParseResults} object."""
-        ret = ParseResults( self.__toklist )
-        ret.__tokdict = self.__tokdict.copy()
-        ret.__parent = self.__parent
-        ret.__accumNames.update( self.__accumNames )
-        ret.__name = self.__name
-        return ret
-
-    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
-        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
-        nl = "\n"
-        out = []
-        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
-                                                            for v in vlist ] )
-        nextLevelIndent = indent + "  "
-
-        # collapse out indents if formatting is not desired
-        if not formatted:
-            indent = ""
-            nextLevelIndent = ""
-            nl = ""
-
-        selfTag = None
-        if doctag is not None:
-            selfTag = doctag
-        else:
-            if self.__name:
-                selfTag = self.__name
-
-        if not selfTag:
-            if namedItemsOnly:
-                return ""
-            else:
-                selfTag = "ITEM"
-
-        out += [ nl, indent, "<", selfTag, ">" ]
-
-        worklist = self.__toklist
-        for i,res in enumerate(worklist):
-            if isinstance(res,ParseResults):
-                if i in namedItems:
-                    out += [ res.asXML(namedItems[i],
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-                else:
-                    out += [ res.asXML(None,
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-            else:
-                # individual token, see if there is a name for it
-                resTag = None
-                if i in namedItems:
-                    resTag = namedItems[i]
-                if not resTag:
-                    if namedItemsOnly:
-                        continue
-                    else:
-                        resTag = "ITEM"
-                xmlBodyText = _xml_escape(_ustr(res))
-                out += [ nl, nextLevelIndent, "<", resTag, ">",
-                                                xmlBodyText,
-                                                "</", resTag, ">" ]
-
-        out += [ nl, indent, "</", selfTag, ">" ]
-        return "".join(out)
-
-    def __lookup(self,sub):
-        for k,vlist in self.__tokdict.items():
-            for v,loc in vlist:
-                if sub is v:
-                    return k
-        return None
-
-    def getName(self):
-        """Returns the results name for this token expression."""
-        if self.__name:
-            return self.__name
-        elif self.__parent:
-            par = self.__parent()
-            if par:
-                return par.__lookup(self)
-            else:
-                return None
-        elif (len(self) == 1 and
-               len(self.__tokdict) == 1 and
-               self.__tokdict.values()[0][0][1] in (0,-1)):
-            return self.__tokdict.keys()[0]
-        else:
-            return None
-
-    def dump(self,indent='',depth=0):
-        """Diagnostic method for listing out the contents of a C{ParseResults}.
-           Accepts an optional C{indent} argument so that this string can be embedded
-           in a nested display of other data."""
-        out = []
-        out.append( indent+_ustr(self.asList()) )
-        keys = self.items()
-        keys.sort()
-        for k,v in keys:
-            if out:
-                out.append('\n')
-            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
-            if isinstance(v,ParseResults):
-                if v.keys():
-                    out.append( v.dump(indent,depth+1) )
-                else:
-                    out.append(_ustr(v))
-            else:
-                out.append(_ustr(v))
-        return "".join(out)
-
-    # add support for pickle protocol
-    def __getstate__(self):
-        return ( self.__toklist,
-                 ( self.__tokdict.copy(),
-                   self.__parent is not None and self.__parent() or None,
-                   self.__accumNames,
-                   self.__name ) )
-
-    def __setstate__(self,state):
-        self.__toklist = state[0]
-        (self.__tokdict,
-         par,
-         inAccumNames,
-         self.__name) = state[1]
-        self.__accumNames = {}
-        self.__accumNames.update(inAccumNames)
-        if par is not None:
-            self.__parent = wkref(par)
-        else:
-            self.__parent = None
-
-    def __dir__(self):
-        return dir(super(ParseResults,self)) + list(self.keys())
-
-def col (loc,strg):
-    """Returns current column within a string, counting newlines as line separators.
-   The first column is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
-
-def lineno(loc,strg):
-    """Returns current line number within a string, counting newlines as line separators.
-   The first line is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return strg.count("\n",0,loc) + 1
-
-def line( loc, strg ):
-    """Returns the line of text containing loc within a string, counting newlines as line separators.
-       """
-    lastCR = strg.rfind("\n", 0, loc)
-    nextCR = strg.find("\n", loc)
-    if nextCR >= 0:
-        return strg[lastCR+1:nextCR]
-    else:
-        return strg[lastCR+1:]
-
-def _defaultStartDebugAction( instring, loc, expr ):
-    print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-
-def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
-    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
-
-def _defaultExceptionDebugAction( instring, loc, expr, exc ):
-    print ("Exception raised:" + _ustr(exc))
-
-def nullDebugAction(*args):
-    """'Do-nothing' debug action, to suppress debugging output during parsing."""
-    pass
-
-'decorator to trim function calls to match the arity of the target'
-def _trim_arity(func, maxargs=2):
-    if func in singleArgBuiltins:
-        return lambda s,l,t: func(t)
-    limit = [0]
-    def wrapper(*args):
-        while 1:
-            try:
-                return func(*args[limit[0]:])
-            except TypeError:
-                if limit[0] <= maxargs:
-                    limit[0] += 1
-                    continue
-                raise
-    return wrapper
-    
-class ParserElement(object):
-    """Abstract base level parser element class."""
-    DEFAULT_WHITE_CHARS = " \n\t\r"
-    verbose_stacktrace = False
-
-    def setDefaultWhitespaceChars( chars ):
-        """Overrides the default whitespace chars
-        """
-        ParserElement.DEFAULT_WHITE_CHARS = chars
-    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
-
-    def inlineLiteralsUsing(cls):
-        """
-        Set class to be used for inclusion of string literals into a parser.
-        """
-        ParserElement.literalStringClass = cls
-    inlineLiteralsUsing = staticmethod(inlineLiteralsUsing)
-
-    def __init__( self, savelist=False ):
-        self.parseAction = list()
-        self.failAction = None
-        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
-        self.strRepr = None
-        self.resultsName = None
-        self.saveAsList = savelist
-        self.skipWhitespace = True
-        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        self.copyDefaultWhiteChars = True
-        self.mayReturnEmpty = False # used when checking for left-recursion
-        self.keepTabs = False
-        self.ignoreExprs = list()
-        self.debug = False
-        self.streamlined = False
-        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
-        self.errmsg = ""
-        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
-        self.debugActions = ( None, None, None ) #custom debug actions
-        self.re = None
-        self.callPreparse = True # used to avoid redundant calls to preParse
-        self.callDuringTry = False
-
-    def copy( self ):
-        """Make a copy of this C{ParserElement}.  Useful for defining different parse actions
-           for the same parsing pattern, using copies of the original parse element."""
-        cpy = copy.copy( self )
-        cpy.parseAction = self.parseAction[:]
-        cpy.ignoreExprs = self.ignoreExprs[:]
-        if self.copyDefaultWhiteChars:
-            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        return cpy
-
-    def setName( self, name ):
-        """Define name for this expression, for use in debugging."""
-        self.name = name
-        self.errmsg = "Expected " + self.name
-        if hasattr(self,"exception"):
-            self.exception.msg = self.errmsg
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        """Define name for referencing matching tokens as a nested attribute
-           of the returned parse results.
-           NOTE: this returns a *copy* of the original C{ParserElement} object;
-           this is so that the client can define a basic element, such as an
-           integer, and reference it in multiple places with different names.
-           
-           You can also set results names using the abbreviated syntax,
-           C{expr("name")} in place of C{expr.setResultsName("name")} - 
-           see L{I{__call__}<__call__>}.
-        """
-        newself = self.copy()
-        if name.endswith("*"):
-            name = name[:-1]
-            listAllMatches=True
-        newself.resultsName = name
-        newself.modalResults = not listAllMatches
-        return newself
-
-    def setBreak(self,breakFlag = True):
-        """Method to invoke the Python pdb debugger when this element is
-           about to be parsed. Set C{breakFlag} to True to enable, False to
-           disable.
-        """
-        if breakFlag:
-            _parseMethod = self._parse
-            def breaker(instring, loc, doActions=True, callPreParse=True):
-                import pdb
-                pdb.set_trace()
-                return _parseMethod( instring, loc, doActions, callPreParse )
-            breaker._originalParseMethod = _parseMethod
-            self._parse = breaker
-        else:
-            if hasattr(self._parse,"_originalParseMethod"):
-                self._parse = self._parse._originalParseMethod
-        return self
-
-    def setParseAction( self, *fns, **kwargs ):
-        """Define action to perform when successfully matching parse element definition.
-           Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
-           C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
-            - s   = the original string being parsed (see note below)
-            - loc = the location of the matching substring
-            - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object
-           If the functions in fns modify the tokens, they can return them as the return
-           value from fn, and the modified list of tokens will replace the original.
-           Otherwise, fn does not need to return any value.
-
-           Note: the default parsing behavior is to expand tabs in the input string
-           before starting the parsing process.  See L{I{parseString}<parseString>} for more information
-           on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-           consistent view of the parsed string, the parse location, and line and column
-           positions within the parsed string.
-           """
-        self.parseAction = list(map(_trim_arity, list(fns)))
-        self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def addParseAction( self, *fns, **kwargs ):
-        """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
-        self.parseAction += list(map(_trim_arity, list(fns)))
-        self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def setFailAction( self, fn ):
-        """Define action to perform if parsing fails at this expression.
-           Fail acton fn is a callable function that takes the arguments
-           C{fn(s,loc,expr,err)} where:
-            - s = string being parsed
-            - loc = location where expression match was attempted and failed
-            - expr = the parse expression that failed
-            - err = the exception thrown
-           The function returns no value.  It may throw C{L{ParseFatalException}}
-           if it is desired to stop parsing immediately."""
-        self.failAction = fn
-        return self
-
-    def _skipIgnorables( self, instring, loc ):
-        exprsFound = True
-        while exprsFound:
-            exprsFound = False
-            for e in self.ignoreExprs:
-                try:
-                    while 1:
-                        loc,dummy = e._parse( instring, loc )
-                        exprsFound = True
-                except ParseException:
-                    pass
-        return loc
-
-    def preParse( self, instring, loc ):
-        if self.ignoreExprs:
-            loc = self._skipIgnorables( instring, loc )
-
-        if self.skipWhitespace:
-            wt = self.whiteChars
-            instrlen = len(instring)
-            while loc < instrlen and instring[loc] in wt:
-                loc += 1
-
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        return loc, []
-
-    def postParse( self, instring, loc, tokenlist ):
-        return tokenlist
-
-    #~ @profile
-    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
-        debugging = ( self.debug ) #and doActions )
-
-        if debugging or self.failAction:
-            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-            if (self.debugActions[0] ):
-                self.debugActions[0]( instring, loc, self )
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            try:
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            except ParseBaseException:
-                #~ print ("Exception raised:", err)
-                err = None
-                if self.debugActions[2]:
-                    err = sys.exc_info()[1]
-                    self.debugActions[2]( instring, tokensStart, self, err )
-                if self.failAction:
-                    if err is None:
-                        err = sys.exc_info()[1]
-                    self.failAction( instring, tokensStart, self, err )
-                raise
-        else:
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            if self.mayIndexError or loc >= len(instring):
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            else:
-                loc,tokens = self.parseImpl( instring, preloc, doActions )
-
-        tokens = self.postParse( instring, loc, tokens )
-
-        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
-        if self.parseAction and (doActions or self.callDuringTry):
-            if debugging:
-                try:
-                    for fn in self.parseAction:
-                        tokens = fn( instring, tokensStart, retTokens )
-                        if tokens is not None:
-                            retTokens = ParseResults( tokens,
-                                                      self.resultsName,
-                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                      modal=self.modalResults )
-                except ParseBaseException:
-                    #~ print "Exception raised in user parse action:", err
-                    if (self.debugActions[2] ):
-                        err = sys.exc_info()[1]
-                        self.debugActions[2]( instring, tokensStart, self, err )
-                    raise
-            else:
-                for fn in self.parseAction:
-                    tokens = fn( instring, tokensStart, retTokens )
-                    if tokens is not None:
-                        retTokens = ParseResults( tokens,
-                                                  self.resultsName,
-                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                  modal=self.modalResults )
-
-        if debugging:
-            #~ print ("Matched",self,"->",retTokens.asList())
-            if (self.debugActions[1] ):
-                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
-
-        return loc, retTokens
-
-    def tryParse( self, instring, loc ):
-        try:
-            return self._parse( instring, loc, doActions=False )[0]
-        except ParseFatalException:
-            raise ParseException( instring, loc, self.errmsg, self)
-
-    # this method gets repeatedly called during backtracking with the same arguments -
-    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
-    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
-        lookup = (self,instring,loc,callPreParse,doActions)
-        if lookup in ParserElement._exprArgCache:
-            value = ParserElement._exprArgCache[ lookup ]
-            if isinstance(value, Exception):
-                raise value
-            return (value[0],value[1].copy())
-        else:
-            try:
-                value = self._parseNoCache( instring, loc, doActions, callPreParse )
-                ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
-                return value
-            except ParseBaseException:
-                pe = sys.exc_info()[1]
-                ParserElement._exprArgCache[ lookup ] = pe
-                raise
-
-    _parse = _parseNoCache
-
-    # argument cache for optimizing repeated calls when backtracking through recursive expressions
-    _exprArgCache = {}
-    def resetCache():
-        ParserElement._exprArgCache.clear()
-    resetCache = staticmethod(resetCache)
-
-    _packratEnabled = False
-    def enablePackrat():
-        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
-           Repeated parse attempts at the same string location (which happens
-           often in many complex grammars) can immediately return a cached value,
-           instead of re-executing parsing/validating code.  Memoizing is done of
-           both valid results and parsing exceptions.
-
-           This speedup may break existing programs that use parse actions that
-           have side-effects.  For this reason, packrat parsing is disabled when
-           you first import pyparsing.  To activate the packrat feature, your
-           program must call the class method C{ParserElement.enablePackrat()}.  If
-           your program uses C{psyco} to "compile as you go", you must call
-           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,
-           Python will crash.  For best results, call C{enablePackrat()} immediately
-           after importing pyparsing.
-        """
-        if not ParserElement._packratEnabled:
-            ParserElement._packratEnabled = True
-            ParserElement._parse = ParserElement._parseCache
-    enablePackrat = staticmethod(enablePackrat)
-
-    def parseString( self, instring, parseAll=False ):
-        """Execute the parse expression with the given string.
-           This is the main interface to the client code, once the complete
-           expression has been built.
-
-           If you want the grammar to require that the entire input string be
-           successfully parsed, then set C{parseAll} to True (equivalent to ending
-           the grammar with C{L{StringEnd()}}).
-
-           Note: C{parseString} implicitly calls C{expandtabs()} on the input string,
-           in order to report proper column numbers in parse actions.
-           If the input string contains tabs and
-           the grammar uses parse actions that use the C{loc} argument to index into the
-           string being parsed, you can ensure you have a consistent view of the input
-           string by:
-            - calling C{parseWithTabs} on your grammar before calling C{parseString}
-              (see L{I{parseWithTabs}<parseWithTabs>})
-            - define your parse action using the full C{(s,loc,toks)} signature, and
-              reference the input string using the parse action's C{s} argument
-            - explictly expand the tabs in your input string before calling
-              C{parseString}
-        """
-        ParserElement.resetCache()
-        if not self.streamlined:
-            self.streamline()
-            #~ self.saveAsList = True
-        for e in self.ignoreExprs:
-            e.streamline()
-        if not self.keepTabs:
-            instring = instring.expandtabs()
-        try:
-            loc, tokens = self._parse( instring, 0 )
-            if parseAll:
-                loc = self.preParse( instring, loc )
-                se = Empty() + StringEnd()
-                se._parse( instring, loc )
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-        else:
-            return tokens
-
-    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
-        """Scan the input string for expression matches.  Each match will return the
-           matching tokens, start location, and end location.  May be called with optional
-           C{maxMatches} argument, to clip scanning after 'n' matches are found.  If
-           C{overlap} is specified, then overlapping matches will be reported.
-
-           Note that the start and end locations are reported relative to the string
-           being parsed.  See L{I{parseString}<parseString>} for more information on parsing
-           strings with embedded tabs."""
-        if not self.streamlined:
-            self.streamline()
-        for e in self.ignoreExprs:
-            e.streamline()
-
-        if not self.keepTabs:
-            instring = _ustr(instring).expandtabs()
-        instrlen = len(instring)
-        loc = 0
-        preparseFn = self.preParse
-        parseFn = self._parse
-        ParserElement.resetCache()
-        matches = 0
-        try:
-            while loc <= instrlen and matches < maxMatches:
-                try:
-                    preloc = preparseFn( instring, loc )
-                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
-                except ParseException:
-                    loc = preloc+1
-                else:
-                    if nextLoc > loc:
-                        matches += 1
-                        yield tokens, preloc, nextLoc
-                        if overlap:
-                            nextloc = preparseFn( instring, loc )
-                            if nextloc > loc:
-                                loc = nextLoc
-                            else:
-                                loc += 1
-                        else:
-                            loc = nextLoc
-                    else:
-                        loc = preloc+1
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def transformString( self, instring ):
-        """Extension to C{L{scanString}}, to modify matching text with modified tokens that may
-           be returned from a parse action.  To use C{transformString}, define a grammar and
-           attach a parse action to it that modifies the returned token list.
-           Invoking C{transformString()} on a target string will then scan for matches,
-           and replace the matched text patterns according to the logic in the parse
-           action.  C{transformString()} returns the resulting transformed string."""
-        out = []
-        lastE = 0
-        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
-        # keep string locs straight between transformString and scanString
-        self.keepTabs = True
-        try:
-            for t,s,e in self.scanString( instring ):
-                out.append( instring[lastE:s] )
-                if t:
-                    if isinstance(t,ParseResults):
-                        out += t.asList()
-                    elif isinstance(t,list):
-                        out += t
-                    else:
-                        out.append(t)
-                lastE = e
-            out.append(instring[lastE:])
-            out = [o for o in out if o]
-            return "".join(map(_ustr,_flatten(out)))
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def searchString( self, instring, maxMatches=_MAX_INT ):
-        """Another extension to C{L{scanString}}, simplifying the access to the tokens found
-           to match the given parse expression.  May be called with optional
-           C{maxMatches} argument, to clip searching after 'n' matches are found.
-        """
-        try:
-            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def __add__(self, other ):
-        """Implementation of + operator - returns C{L{And}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, other ] )
-
-    def __radd__(self, other ):
-        """Implementation of + operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other + self
-
-    def __sub__(self, other):
-        """Implementation of - operator, returns C{L{And}} with error stop"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, And._ErrorStop(), other ] )
-
-    def __rsub__(self, other ):
-        """Implementation of - operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other - self
-
-    def __mul__(self,other):
-        """Implementation of * operator, allows use of C{expr * 3} in place of
-           C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer
-           tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples
-           may also include C{None} as in:
-            - C{expr*(n,None)} or C{expr*(n,)} is equivalent
-              to C{expr*n + L{ZeroOrMore}(expr)}
-              (read as "at least n instances of C{expr}")
-            - C{expr*(None,n)} is equivalent to C{expr*(0,n)}
-              (read as "0 to n instances of C{expr}")
-            - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}
-            - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}
-
-           Note that C{expr*(None,n)} does not raise an exception if
-           more than n exprs exist in the input stream; that is,
-           C{expr*(None,n)} does not enforce a maximum number of expr
-           occurrences.  If this behavior is desired, then write
-           C{expr*(None,n) + ~expr}
-
-        """
-        if isinstance(other,int):
-            minElements, optElements = other,0
-        elif isinstance(other,tuple):
-            other = (other + (None, None))[:2]
-            if other[0] is None:
-                other = (0, other[1])
-            if isinstance(other[0],int) and other[1] is None:
-                if other[0] == 0:
-                    return ZeroOrMore(self)
-                if other[0] == 1:
-                    return OneOrMore(self)
-                else:
-                    return self*other[0] + ZeroOrMore(self)
-            elif isinstance(other[0],int) and isinstance(other[1],int):
-                minElements, optElements = other
-                optElements -= minElements
-            else:
-                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
-        else:
-            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
-
-        if minElements < 0:
-            raise ValueError("cannot multiply ParserElement by negative value")
-        if optElements < 0:
-            raise ValueError("second tuple value must be greater or equal to first tuple value")
-        if minElements == optElements == 0:
-            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
-
-        if (optElements):
-            def makeOptionalList(n):
-                if n>1:
-                    return Optional(self + makeOptionalList(n-1))
-                else:
-                    return Optional(self)
-            if minElements:
-                if minElements == 1:
-                    ret = self + makeOptionalList(optElements)
-                else:
-                    ret = And([self]*minElements) + makeOptionalList(optElements)
-            else:
-                ret = makeOptionalList(optElements)
-        else:
-            if minElements == 1:
-                ret = self
-            else:
-                ret = And([self]*minElements)
-        return ret
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-
-    def __or__(self, other ):
-        """Implementation of | operator - returns C{L{MatchFirst}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return MatchFirst( [ self, other ] )
-
-    def __ror__(self, other ):
-        """Implementation of | operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other | self
-
-    def __xor__(self, other ):
-        """Implementation of ^ operator - returns C{L{Or}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Or( [ self, other ] )
-
-    def __rxor__(self, other ):
-        """Implementation of ^ operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other ^ self
-
-    def __and__(self, other ):
-        """Implementation of & operator - returns C{L{Each}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Each( [ self, other ] )
-
-    def __rand__(self, other ):
-        """Implementation of & operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other & self
-
-    def __invert__( self ):
-        """Implementation of ~ operator - returns C{L{NotAny}}"""
-        return NotAny( self )
-
-    def __call__(self, name):
-        """Shortcut for C{L{setResultsName}}, with C{listAllMatches=default}::
-             userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
-           could be written as::
-             userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
-             
-           If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be
-           passed as C{True}.
-           """
-        return self.setResultsName(name)
-
-    def suppress( self ):
-        """Suppresses the output of this C{ParserElement}; useful to keep punctuation from
-           cluttering up returned output.
-        """
-        return Suppress( self )
-
-    def leaveWhitespace( self ):
-        """Disables the skipping of whitespace before matching the characters in the
-           C{ParserElement}'s defined pattern.  This is normally only used internally by
-           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
-        """
-        self.skipWhitespace = False
-        return self
-
-    def setWhitespaceChars( self, chars ):
-        """Overrides the default whitespace chars
-        """
-        self.skipWhitespace = True
-        self.whiteChars = chars
-        self.copyDefaultWhiteChars = False
-        return self
-
-    def parseWithTabs( self ):
-        """Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string.
-           Must be called before C{parseString} when the input grammar contains elements that
-           match C{<TAB>} characters."""
-        self.keepTabs = True
-        return self
-
-    def ignore( self, other ):
-        """Define expression to be ignored (e.g., comments) while doing pattern
-           matching; may be called repeatedly, to define multiple comment or other
-           ignorable patterns.
-        """
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                self.ignoreExprs.append( other.copy() )
-        else:
-            self.ignoreExprs.append( Suppress( other.copy() ) )
-        return self
-
-    def setDebugActions( self, startAction, successAction, exceptionAction ):
-        """Enable display of debugging messages while doing pattern matching."""
-        self.debugActions = (startAction or _defaultStartDebugAction,
-                             successAction or _defaultSuccessDebugAction,
-                             exceptionAction or _defaultExceptionDebugAction)
-        self.debug = True
-        return self
-
-    def setDebug( self, flag=True ):
-        """Enable display of debugging messages while doing pattern matching.
-           Set C{flag} to True to enable, False to disable."""
-        if flag:
-            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
-        else:
-            self.debug = False
-        return self
-
-    def __str__( self ):
-        return self.name
-
-    def __repr__( self ):
-        return _ustr(self)
-
-    def streamline( self ):
-        self.streamlined = True
-        self.strRepr = None
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        pass
-
-    def validate( self, validateTrace=[] ):
-        """Check defined expressions for valid structure, check for infinite recursive definitions."""
-        self.checkRecursion( [] )
-
-    def parseFile( self, file_or_filename, parseAll=False ):
-        """Execute the parse expression on the given file or filename.
-           If a filename is specified (instead of a file object),
-           the entire file is opened, read, and closed before parsing.
-        """
-        try:
-            file_contents = file_or_filename.read()
-        except AttributeError:
-            f = open(file_or_filename, "r")
-            file_contents = f.read()
-            f.close()
-        try:
-            return self.parseString(file_contents, parseAll)
-        except ParseBaseException:
-            # catch and re-raise exception from here, clears out pyparsing internal stack trace
-            exc = sys.exc_info()[1]
-            raise exc
-
-    def getException(self):
-        return ParseException("",0,self.errmsg,self)
-
-    def __getattr__(self,aname):
-        if aname == "myException":
-            self.myException = ret = self.getException();
-            return ret;
-        else:
-            raise AttributeError("no such attribute " + aname)
-
-    def __eq__(self,other):
-        if isinstance(other, ParserElement):
-            return self is other or self.__dict__ == other.__dict__
-        elif isinstance(other, basestring):
-            try:
-                self.parseString(_ustr(other), parseAll=True)
-                return True
-            except ParseBaseException:
-                return False
-        else:
-            return super(ParserElement,self)==other
-
-    def __ne__(self,other):
-        return not (self == other)
-
-    def __hash__(self):
-        return hash(id(self))
-
-    def __req__(self,other):
-        return self == other
-
-    def __rne__(self,other):
-        return not (self == other)
-
-
-class Token(ParserElement):
-    """Abstract C{ParserElement} subclass, for defining atomic matching patterns."""
-    def __init__( self ):
-        super(Token,self).__init__( savelist=False )
-
-    def setName(self, name):
-        s = super(Token,self).setName(name)
-        self.errmsg = "Expected " + self.name
-        return s
-
-
-class Empty(Token):
-    """An empty token, will always match."""
-    def __init__( self ):
-        super(Empty,self).__init__()
-        self.name = "Empty"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-
-class NoMatch(Token):
-    """A token that will never match."""
-    def __init__( self ):
-        super(NoMatch,self).__init__()
-        self.name = "NoMatch"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.errmsg = "Unmatchable token"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-
-class Literal(Token):
-    """Token to exactly match a specified string."""
-    def __init__( self, matchString ):
-        super(Literal,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Literal; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-            self.__class__ = Empty
-        self.name = '"%s"' % _ustr(self.match)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-
-    # Performance tuning: this routine gets called a *lot*
-    # if this is a single character match string  and the first character matches,
-    # short-circuit as quickly as possible, and avoid calling startswith
-    #~ @profile
-    def parseImpl( self, instring, loc, doActions=True ):
-        if (instring[loc] == self.firstMatchChar and
-            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
-            return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-_L = Literal
-ParserElement.literalStringClass = Literal
-
-class Keyword(Token):
-    """Token to exactly match a specified string as a keyword, that is, it must be
-       immediately followed by a non-keyword character.  Compare with C{L{Literal}}::
-         Literal("if") will match the leading C{'if'} in C{'ifAndOnlyIf'}.
-         Keyword("if") will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}
-       Accepts two optional constructor arguments in addition to the keyword string:
-       C{identChars} is a string of characters that would be valid identifier characters,
-       defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive
-       matching, default is C{False}.
-    """
-    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
-
-    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
-        super(Keyword,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Keyword; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-        self.name = '"%s"' % self.match
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-        self.caseless = caseless
-        if caseless:
-            self.caselessmatch = matchString.upper()
-            identChars = identChars.upper()
-        self.identChars = set(identChars)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.caseless:
-            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
-                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        else:
-            if (instring[loc] == self.firstMatchChar and
-                (self.matchLen==1 or instring.startswith(self.match,loc)) and
-                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
-                (loc == 0 or instring[loc-1] not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-    def copy(self):
-        c = super(Keyword,self).copy()
-        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
-        return c
-
-    def setDefaultKeywordChars( chars ):
-        """Overrides the default Keyword chars
-        """
-        Keyword.DEFAULT_KEYWORD_CHARS = chars
-    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
-
-class CaselessLiteral(Literal):
-    """Token to match a specified string, ignoring case of letters.
-       Note: the matched results will always be in the case of the given
-       match string, NOT the case of the input text.
-    """
-    def __init__( self, matchString ):
-        super(CaselessLiteral,self).__init__( matchString.upper() )
-        # Preserve the defining literal.
-        self.returnString = matchString
-        self.name = "'%s'" % self.returnString
-        self.errmsg = "Expected " + self.name
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[ loc:loc+self.matchLen ].upper() == self.match:
-            return loc+self.matchLen, self.returnString
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class CaselessKeyword(Keyword):
-    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
-        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
-            return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class Word(Token):
-    """Token for matching words composed of allowed character sets.
-       Defined with string containing all allowed initial characters,
-       an optional string containing allowed body characters (if omitted,
-       defaults to the initial character set), and an optional minimum,
-       maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction. An optional
-       C{exclude} parameter can list characters that might be found in 
-       the input C{bodyChars} string; useful to define a word of all printables
-       except for one or two characters, for instance.
-    """
-    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
-        super(Word,self).__init__()
-        if excludeChars:
-            initChars = ''.join([c for c in initChars if c not in excludeChars])
-            if bodyChars:
-                bodyChars = ''.join([c for c in bodyChars if c not in excludeChars])
-        self.initCharsOrig = initChars
-        self.initChars = set(initChars)
-        if bodyChars :
-            self.bodyCharsOrig = bodyChars
-            self.bodyChars = set(bodyChars)
-        else:
-            self.bodyCharsOrig = initChars
-            self.bodyChars = set(initChars)
-
-        self.maxSpecified = max > 0
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.asKeyword = asKeyword
-
-        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
-            if self.bodyCharsOrig == self.initCharsOrig:
-                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
-            elif len(self.bodyCharsOrig) == 1:
-                self.reString = "%s[%s]*" % \
-                                      (re.escape(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            else:
-                self.reString = "[%s][%s]*" % \
-                                      (_escapeRegexRangeChars(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            if self.asKeyword:
-                self.reString = r"\b"+self.reString+r"\b"
-            try:
-                self.re = re.compile( self.reString )
-            except:
-                self.re = None
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.re:
-            result = self.re.match(instring,loc)
-            if not result:
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-
-            loc = result.end()
-            return loc, result.group()
-
-        if not(instring[ loc ] in self.initChars):
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        start = loc
-        loc += 1
-        instrlen = len(instring)
-        bodychars = self.bodyChars
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, instrlen )
-        while loc < maxloc and instring[loc] in bodychars:
-            loc += 1
-
-        throwException = False
-        if loc - start < self.minLen:
-            throwException = True
-        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
-            throwException = True
-        if self.asKeyword:
-            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
-                throwException = True
-
-        if throwException:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(Word,self).__str__()
-        except:
-            pass
-
-
-        if self.strRepr is None:
-
-            def charsAsStr(s):
-                if len(s)>4:
-                    return s[:4]+"..."
-                else:
-                    return s
-
-            if ( self.initCharsOrig != self.bodyCharsOrig ):
-                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
-            else:
-                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
-
-        return self.strRepr
-
-
-class Regex(Token):
-    """Token for matching strings that match a given regular expression.
-       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
-    """
-    compiledREtype = type(re.compile("[A-Z]"))
-    def __init__( self, pattern, flags=0):
-        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""
-        super(Regex,self).__init__()
-
-        if isinstance(pattern, basestring):
-            if len(pattern) == 0:
-                warnings.warn("null string passed to Regex; use Empty() instead",
-                        SyntaxWarning, stacklevel=2)
-
-            self.pattern = pattern
-            self.flags = flags
-
-            try:
-                self.re = re.compile(self.pattern, self.flags)
-                self.reString = self.pattern
-            except sre_constants.error:
-                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
-                    SyntaxWarning, stacklevel=2)
-                raise
-
-        elif isinstance(pattern, Regex.compiledREtype):
-            self.re = pattern
-            self.pattern = \
-            self.reString = str(pattern)
-            self.flags = flags
-            
-        else:
-            raise ValueError("Regex may only be constructed with a string or a compiled RE object")
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = self.re.match(instring,loc)
-        if not result:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        loc = result.end()
-        d = result.groupdict()
-        ret = ParseResults(result.group())
-        if d:
-            for k in d:
-                ret[k] = d[k]
-        return loc,ret
-
-    def __str__( self ):
-        try:
-            return super(Regex,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "Re:(%s)" % repr(self.pattern)
-
-        return self.strRepr
-
-
-class QuotedString(Token):
-    """Token for matching strings that are delimited by quoting characters.
-    """
-    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
-        """
-           Defined with the following parameters:
-            - quoteChar - string of one or more characters defining the quote delimiting string
-            - escChar - character to escape quotes, typically backslash (default=None)
-            - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
-            - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})
-            - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})
-            - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)
-        """
-        super(QuotedString,self).__init__()
-
-        # remove white space from quote chars - wont work anyway
-        quoteChar = quoteChar.strip()
-        if len(quoteChar) == 0:
-            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-            raise SyntaxError()
-
-        if endQuoteChar is None:
-            endQuoteChar = quoteChar
-        else:
-            endQuoteChar = endQuoteChar.strip()
-            if len(endQuoteChar) == 0:
-                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-                raise SyntaxError()
-
-        self.quoteChar = quoteChar
-        self.quoteCharLen = len(quoteChar)
-        self.firstQuoteChar = quoteChar[0]
-        self.endQuoteChar = endQuoteChar
-        self.endQuoteCharLen = len(endQuoteChar)
-        self.escChar = escChar
-        self.escQuote = escQuote
-        self.unquoteResults = unquoteResults
-
-        if multiline:
-            self.flags = re.MULTILINE | re.DOTALL
-            self.pattern = r'%s(?:[^%s%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        else:
-            self.flags = 0
-            self.pattern = r'%s(?:[^%s\n\r%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        if len(self.endQuoteChar) > 1:
-            self.pattern += (
-                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
-                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
-                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
-                )
-        if escQuote:
-            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
-        if escChar:
-            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
-            charset = ''.join(set(self.quoteChar[0]+self.endQuoteChar[0])).replace('^',r'\^').replace('-',r'\-')
-            self.escCharReplacePattern = re.escape(self.escChar)+("([%s])" % charset)
-        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
-
-        try:
-            self.re = re.compile(self.pattern, self.flags)
-            self.reString = self.pattern
-        except sre_constants.error:
-            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
-                SyntaxWarning, stacklevel=2)
-            raise
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
-        if not result:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        loc = result.end()
-        ret = result.group()
-
-        if self.unquoteResults:
-
-            # strip off quotes
-            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
-
-            if isinstance(ret,basestring):
-                # replace escaped characters
-                if self.escChar:
-                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
-
-                # replace escaped quotes
-                if self.escQuote:
-                    ret = ret.replace(self.escQuote, self.endQuoteChar)
-
-        return loc, ret
-
-    def __str__( self ):
-        try:
-            return super(QuotedString,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
-
-        return self.strRepr
-
-
-class CharsNotIn(Token):
-    """Token for matching words composed of characters *not* in a given set.
-       Defined with string containing all disallowed characters, and an optional
-       minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction.
-    """
-    def __init__( self, notChars, min=1, max=0, exact=0 ):
-        super(CharsNotIn,self).__init__()
-        self.skipWhitespace = False
-        self.notChars = notChars
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = ( self.minLen == 0 )
-        self.mayIndexError = False
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[loc] in self.notChars:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        start = loc
-        loc += 1
-        notchars = self.notChars
-        maxlen = min( start+self.maxLen, len(instring) )
-        while loc < maxlen and \
-              (instring[loc] not in notchars):
-            loc += 1
-
-        if loc - start < self.minLen:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(CharsNotIn, self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            if len(self.notChars) > 4:
-                self.strRepr = "!W:(%s...)" % self.notChars[:4]
-            else:
-                self.strRepr = "!W:(%s)" % self.notChars
-
-        return self.strRepr
-
-class White(Token):
-    """Special matching class for matching whitespace.  Normally, whitespace is ignored
-       by pyparsing grammars.  This class is included when some whitespace structures
-       are significant.  Define with a string containing the whitespace characters to be
-       matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,
-       as defined for the C{L{Word}} class."""
-    whiteStrs = {
-        " " : "<SPC>",
-        "\t": "<TAB>",
-        "\n": "<LF>",
-        "\r": "<CR>",
-        "\f": "<FF>",
-        }
-    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
-        super(White,self).__init__()
-        self.matchWhite = ws
-        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
-        #~ self.leaveWhitespace()
-        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
-        self.mayReturnEmpty = True
-        self.errmsg = "Expected " + self.name
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not(instring[ loc ] in self.matchWhite):
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        start = loc
-        loc += 1
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, len(instring) )
-        while loc < maxloc and instring[loc] in self.matchWhite:
-            loc += 1
-
-        if loc - start < self.minLen:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-
-class _PositionToken(Token):
-    def __init__( self ):
-        super(_PositionToken,self).__init__()
-        self.name=self.__class__.__name__
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-class GoToColumn(_PositionToken):
-    """Token to advance to a specific column of input text; useful for tabular report scraping."""
-    def __init__( self, colno ):
-        super(GoToColumn,self).__init__()
-        self.col = colno
-
-    def preParse( self, instring, loc ):
-        if col(loc,instring) != self.col:
-            instrlen = len(instring)
-            if self.ignoreExprs:
-                loc = self._skipIgnorables( instring, loc )
-            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
-                loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        thiscol = col( loc, instring )
-        if thiscol > self.col:
-            raise ParseException( instring, loc, "Text not in expected column", self )
-        newloc = loc + self.col - thiscol
-        ret = instring[ loc: newloc ]
-        return newloc, ret
-
-class LineStart(_PositionToken):
-    """Matches if current position is at the beginning of a line within the parse string"""
-    def __init__( self ):
-        super(LineStart,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected start of line"
-
-    def preParse( self, instring, loc ):
-        preloc = super(LineStart,self).preParse(instring,loc)
-        if instring[preloc] == "\n":
-            loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not( loc==0 or
-            (loc == self.preParse( instring, 0 )) or
-            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
-            #~ raise ParseException( instring, loc, "Expected start of line" )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        return loc, []
-
-class LineEnd(_PositionToken):
-    """Matches if current position is at the end of a line within the parse string"""
-    def __init__( self ):
-        super(LineEnd,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected end of line"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc<len(instring):
-            if instring[loc] == "\n":
-                return loc+1, "\n"
-            else:
-                #~ raise ParseException( instring, loc, "Expected end of line" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        elif loc == len(instring):
-            return loc+1, []
-        else:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-class StringStart(_PositionToken):
-    """Matches if current position is at the beginning of the parse string"""
-    def __init__( self ):
-        super(StringStart,self).__init__()
-        self.errmsg = "Expected start of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc != 0:
-            # see if entire string up to here is just whitespace and ignoreables
-            if loc != self.preParse( instring, 0 ):
-                #~ raise ParseException( instring, loc, "Expected start of text" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-class StringEnd(_PositionToken):
-    """Matches if current position is at the end of the parse string"""
-    def __init__( self ):
-        super(StringEnd,self).__init__()
-        self.errmsg = "Expected end of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc < len(instring):
-            #~ raise ParseException( instring, loc, "Expected end of text" )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        elif loc == len(instring):
-            return loc+1, []
-        elif loc > len(instring):
-            return loc, []
-        else:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-class WordStart(_PositionToken):
-    """Matches if the current position is at the beginning of a Word, and
-       is not preceded by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of
-       the string being parsed, or at the beginning of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordStart,self).__init__()
-        self.wordChars = set(wordChars)
-        self.errmsg = "Not at the start of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        if loc != 0:
-            if (instring[loc-1] in self.wordChars or
-                instring[loc] not in self.wordChars):
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-class WordEnd(_PositionToken):
-    """Matches if the current position is at the end of a Word, and
-       is not followed by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of
-       the string being parsed, or at the end of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordEnd,self).__init__()
-        self.wordChars = set(wordChars)
-        self.skipWhitespace = False
-        self.errmsg = "Not at the end of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        instrlen = len(instring)
-        if instrlen>0 and loc<instrlen:
-            if (instring[loc] in self.wordChars or
-                instring[loc-1] not in self.wordChars):
-                #~ raise ParseException( instring, loc, "Expected end of word" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-
-class ParseExpression(ParserElement):
-    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
-    def __init__( self, exprs, savelist = False ):
-        super(ParseExpression,self).__init__(savelist)
-        if isinstance( exprs, list ):
-            self.exprs = exprs
-        elif isinstance( exprs, basestring ):
-            self.exprs = [ Literal( exprs ) ]
-        else:
-            try:
-                self.exprs = list( exprs )
-            except TypeError:
-                self.exprs = [ exprs ]
-        self.callPreparse = False
-
-    def __getitem__( self, i ):
-        return self.exprs[i]
-
-    def append( self, other ):
-        self.exprs.append( other )
-        self.strRepr = None
-        return self
-
-    def leaveWhitespace( self ):
-        """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on
-           all contained expressions."""
-        self.skipWhitespace = False
-        self.exprs = [ e.copy() for e in self.exprs ]
-        for e in self.exprs:
-            e.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseExpression, self).ignore( other )
-                for e in self.exprs:
-                    e.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseExpression, self).ignore( other )
-            for e in self.exprs:
-                e.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def __str__( self ):
-        try:
-            return super(ParseExpression,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
-        return self.strRepr
-
-    def streamline( self ):
-        super(ParseExpression,self).streamline()
-
-        for e in self.exprs:
-            e.streamline()
-
-        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
-        # but only if there are no parse actions or resultsNames on the nested And's
-        # (likewise for Or's and MatchFirst's)
-        if ( len(self.exprs) == 2 ):
-            other = self.exprs[0]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = other.exprs[:] + [ self.exprs[1] ]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-            other = self.exprs[-1]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = self.exprs[:-1] + other.exprs[:]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
-        return ret
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        for e in self.exprs:
-            e.validate(tmp)
-        self.checkRecursion( [] )
-        
-    def copy(self):
-        ret = super(ParseExpression,self).copy()
-        ret.exprs = [e.copy() for e in self.exprs]
-        return ret
-
-class And(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found in the given order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'+'} operator.
-    """
-
-    class _ErrorStop(Empty):
-        def __init__(self, *args, **kwargs):
-            super(And._ErrorStop,self).__init__(*args, **kwargs)
-            self.leaveWhitespace()
-
-    def __init__( self, exprs, savelist = True ):
-        super(And,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.setWhitespaceChars( exprs[0].whiteChars )
-        self.skipWhitespace = exprs[0].skipWhitespace
-        self.callPreparse = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        # pass False as last arg to _parse for first element, since we already
-        # pre-parsed the string as part of our And pre-parsing
-        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
-        errorStop = False
-        for e in self.exprs[1:]:
-            if isinstance(e, And._ErrorStop):
-                errorStop = True
-                continue
-            if errorStop:
-                try:
-                    loc, exprtokens = e._parse( instring, loc, doActions )
-                except ParseSyntaxException:
-                    raise
-                except ParseBaseException:
-                    pe = sys.exc_info()[1]
-                    raise ParseSyntaxException(pe)
-                except IndexError:
-                    raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
-            else:
-                loc, exprtokens = e._parse( instring, loc, doActions )
-            if exprtokens or exprtokens.keys():
-                resultlist += exprtokens
-        return loc, resultlist
-
-    def __iadd__(self, other ):
-        if isinstance( other, basestring ):
-            other = Literal( other )
-        return self.append( other ) #And( [ self, other ] )
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-            if not e.mayReturnEmpty:
-                break
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-
-class Or(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the expression that matches the longest string will be used.
-       May be constructed using the C{'^'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(Or,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = False
-        for e in self.exprs:
-            if e.mayReturnEmpty:
-                self.mayReturnEmpty = True
-                break
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxMatchLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                loc2 = e.tryParse( instring, loc )
-            except ParseException:
-                err = sys.exc_info()[1]
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-            else:
-                if loc2 > maxMatchLoc:
-                    maxMatchLoc = loc2
-                    maxMatchExp = e
-
-        if maxMatchLoc < 0:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-        return maxMatchExp._parse( instring, loc, doActions )
-
-    def __ixor__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #Or( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class MatchFirst(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the first one listed is the one that will match.
-       May be constructed using the C{'|'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(MatchFirst,self).__init__(exprs, savelist)
-        if exprs:
-            self.mayReturnEmpty = False
-            for e in self.exprs:
-                if e.mayReturnEmpty:
-                    self.mayReturnEmpty = True
-                    break
-        else:
-            self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                ret = e._parse( instring, loc, doActions )
-                return ret
-            except ParseException, err:
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-
-        # only got here if no expression matched, raise exception for match that made it the furthest
-        else:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-    def __ior__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #MatchFirst( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class Each(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found, but in any order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'&'} operator.
-    """
-    def __init__( self, exprs, savelist = True ):
-        super(Each,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.skipWhitespace = True
-        self.initExprGroups = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.initExprGroups:
-            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
-            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ]
-            self.optionals = opt1 + opt2
-            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
-            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
-            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
-            self.required += self.multirequired
-            self.initExprGroups = False
-        tmpLoc = loc
-        tmpReqd = self.required[:]
-        tmpOpt  = self.optionals[:]
-        matchOrder = []
-
-        keepMatching = True
-        while keepMatching:
-            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
-            failed = []
-            for e in tmpExprs:
-                try:
-                    tmpLoc = e.tryParse( instring, tmpLoc )
-                except ParseException:
-                    failed.append(e)
-                else:
-                    matchOrder.append(e)
-                    if e in tmpReqd:
-                        tmpReqd.remove(e)
-                    elif e in tmpOpt:
-                        tmpOpt.remove(e)
-            if len(failed) == len(tmpExprs):
-                keepMatching = False
-
-        if tmpReqd:
-            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
-            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
-
-        # add any unmatched Optionals, in case they have default values defined
-        matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]
-
-        resultlist = []
-        for e in matchOrder:
-            loc,results = e._parse(instring,loc,doActions)
-            resultlist.append(results)
-
-        finalResults = ParseResults([])
-        for r in resultlist:
-            dups = {}
-            for k in r.keys():
-                if k in finalResults.keys():
-                    tmp = ParseResults(finalResults[k])
-                    tmp += ParseResults(r[k])
-                    dups[k] = tmp
-            finalResults += ParseResults(r)
-            for k,v in dups.items():
-                finalResults[k] = v
-        return loc, finalResults
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class ParseElementEnhance(ParserElement):
-    """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens."""
-    def __init__( self, expr, savelist=False ):
-        super(ParseElementEnhance,self).__init__(savelist)
-        if isinstance( expr, basestring ):
-            expr = Literal(expr)
-        self.expr = expr
-        self.strRepr = None
-        if expr is not None:
-            self.mayIndexError = expr.mayIndexError
-            self.mayReturnEmpty = expr.mayReturnEmpty
-            self.setWhitespaceChars( expr.whiteChars )
-            self.skipWhitespace = expr.skipWhitespace
-            self.saveAsList = expr.saveAsList
-            self.callPreparse = expr.callPreparse
-            self.ignoreExprs.extend(expr.ignoreExprs)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.expr is not None:
-            return self.expr._parse( instring, loc, doActions, callPreParse=False )
-        else:
-            raise ParseException("",loc,self.errmsg,self)
-
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        self.expr = self.expr.copy()
-        if self.expr is not None:
-            self.expr.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseElementEnhance, self).ignore( other )
-                if self.expr is not None:
-                    self.expr.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseElementEnhance, self).ignore( other )
-            if self.expr is not None:
-                self.expr.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def streamline( self ):
-        super(ParseElementEnhance,self).streamline()
-        if self.expr is not None:
-            self.expr.streamline()
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        if self in parseElementList:
-            raise RecursiveGrammarException( parseElementList+[self] )
-        subRecCheckList = parseElementList[:] + [ self ]
-        if self.expr is not None:
-            self.expr.checkRecursion( subRecCheckList )
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        if self.expr is not None:
-            self.expr.validate(tmp)
-        self.checkRecursion( [] )
-
-    def __str__( self ):
-        try:
-            return super(ParseElementEnhance,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None and self.expr is not None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
-        return self.strRepr
-
-
-class FollowedBy(ParseElementEnhance):
-    """Lookahead matching of the given parse expression.  C{FollowedBy}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression matches at the current
-    position.  C{FollowedBy} always returns a null token list."""
-    def __init__( self, expr ):
-        super(FollowedBy,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        self.expr.tryParse( instring, loc )
-        return loc, []
-
-
-class NotAny(ParseElementEnhance):
-    """Lookahead to disallow matching with the given parse expression.  C{NotAny}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression does *not* match at the current
-    position.  Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny}
-    always returns a null token list.  May be constructed using the '~' operator."""
-    def __init__( self, expr ):
-        super(NotAny,self).__init__(expr)
-        #~ self.leaveWhitespace()
-        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
-        self.mayReturnEmpty = True
-        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            self.expr.tryParse( instring, loc )
-        except (ParseException,IndexError):
-            pass
-        else:
-            #~ raise ParseException(instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        return loc, []
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "~{" + _ustr(self.expr) + "}"
-
-        return self.strRepr
-
-
-class ZeroOrMore(ParseElementEnhance):
-    """Optional repetition of zero or more of the given expression."""
-    def __init__( self, expr ):
-        super(ZeroOrMore,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        tokens = []
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-
-class OneOrMore(ParseElementEnhance):
-    """Repetition of one or more of the given expression."""
-    def parseImpl( self, instring, loc, doActions=True ):
-        # must be at least one
-        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        try:
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + _ustr(self.expr) + "}..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-class _NullToken(object):
-    def __bool__(self):
-        return False
-    __nonzero__ = __bool__
-    def __str__(self):
-        return ""
-
-_optionalNotMatched = _NullToken()
-class Optional(ParseElementEnhance):
-    """Optional matching of the given expression.
-       A default return string can also be specified, if the optional expression
-       is not found.
-    """
-    def __init__( self, exprs, default=_optionalNotMatched ):
-        super(Optional,self).__init__( exprs, savelist=False )
-        self.defaultValue = default
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        except (ParseException,IndexError):
-            if self.defaultValue is not _optionalNotMatched:
-                if self.expr.resultsName:
-                    tokens = ParseResults([ self.defaultValue ])
-                    tokens[self.expr.resultsName] = self.defaultValue
-                else:
-                    tokens = [ self.defaultValue ]
-            else:
-                tokens = []
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]"
-
-        return self.strRepr
-
-
-class SkipTo(ParseElementEnhance):
-    """Token for skipping over all undefined text until the matched expression is found.
-       If C{include} is set to true, the matched expression is also parsed (the skipped text
-       and matched expression are returned as a 2-element list).  The C{ignore}
-       argument is used to define grammars (typically quoted strings and comments) that
-       might contain false matches.
-    """
-    def __init__( self, other, include=False, ignore=None, failOn=None ):
-        super( SkipTo, self ).__init__( other )
-        self.ignoreExpr = ignore
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.includeMatch = include
-        self.asList = False
-        if failOn is not None and isinstance(failOn, basestring):
-            self.failOn = Literal(failOn)
-        else:
-            self.failOn = failOn
-        self.errmsg = "No match found for "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        startLoc = loc
-        instrlen = len(instring)
-        expr = self.expr
-        failParse = False
-        while loc <= instrlen:
-            try:
-                if self.failOn:
-                    try:
-                        self.failOn.tryParse(instring, loc)
-                    except ParseBaseException:
-                        pass
-                    else:
-                        failParse = True
-                        raise ParseException(instring, loc, "Found expression " + str(self.failOn))
-                    failParse = False
-                if self.ignoreExpr is not None:
-                    while 1:
-                        try:
-                            loc = self.ignoreExpr.tryParse(instring,loc)
-                            # print "found ignoreExpr, advance to", loc
-                        except ParseBaseException:
-                            break
-                expr._parse( instring, loc, doActions=False, callPreParse=False )
-                skipText = instring[startLoc:loc]
-                if self.includeMatch:
-                    loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
-                    if mat:
-                        skipRes = ParseResults( skipText )
-                        skipRes += mat
-                        return loc, [ skipRes ]
-                    else:
-                        return loc, [ skipText ]
-                else:
-                    return loc, [ skipText ]
-            except (ParseException,IndexError):
-                if failParse:
-                    raise
-                else:
-                    loc += 1
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class Forward(ParseElementEnhance):
-    """Forward declaration of an expression to be defined later -
-       used for recursive grammars, such as algebraic infix notation.
-       When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.
-
-       Note: take care when assigning to C{Forward} not to overlook precedence of operators.
-       Specifically, '|' has a lower precedence than '<<', so that::
-          fwdExpr << a | b | c
-       will actually be evaluated as::
-          (fwdExpr << a) | b | c
-       thereby leaving b and c out as parseable alternatives.  It is recommended that you
-       explicitly group the values inserted into the C{Forward}::
-          fwdExpr << (a | b | c)
-       Converting to use the '<<=' operator instead will avoid this problem.
-    """
-    def __init__( self, other=None ):
-        super(Forward,self).__init__( other, savelist=False )
-
-    def __lshift__( self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass(other)
-        self.expr = other
-        self.mayReturnEmpty = other.mayReturnEmpty
-        self.strRepr = None
-        self.mayIndexError = self.expr.mayIndexError
-        self.mayReturnEmpty = self.expr.mayReturnEmpty
-        self.setWhitespaceChars( self.expr.whiteChars )
-        self.skipWhitespace = self.expr.skipWhitespace
-        self.saveAsList = self.expr.saveAsList
-        self.ignoreExprs.extend(self.expr.ignoreExprs)
-        return None
-    __ilshift__ = __lshift__
-    
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        return self
-
-    def streamline( self ):
-        if not self.streamlined:
-            self.streamlined = True
-            if self.expr is not None:
-                self.expr.streamline()
-        return self
-
-    def validate( self, validateTrace=[] ):
-        if self not in validateTrace:
-            tmp = validateTrace[:]+[self]
-            if self.expr is not None:
-                self.expr.validate(tmp)
-        self.checkRecursion([])
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        self._revertClass = self.__class__
-        self.__class__ = _ForwardNoRecurse
-        try:
-            if self.expr is not None:
-                retString = _ustr(self.expr)
-            else:
-                retString = "None"
-        finally:
-            self.__class__ = self._revertClass
-        return self.__class__.__name__ + ": " + retString
-
-    def copy(self):
-        if self.expr is not None:
-            return super(Forward,self).copy()
-        else:
-            ret = Forward()
-            ret << self
-            return ret
-
-class _ForwardNoRecurse(Forward):
-    def __str__( self ):
-        return "..."
-
-class TokenConverter(ParseElementEnhance):
-    """Abstract subclass of C{ParseExpression}, for converting parsed results."""
-    def __init__( self, expr, savelist=False ):
-        super(TokenConverter,self).__init__( expr )#, savelist )
-        self.saveAsList = False
-
-class Upcase(TokenConverter):
-    """Converter to upper case all matching tokens."""
-    def __init__(self, *args):
-        super(Upcase,self).__init__(*args)
-        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
-                       DeprecationWarning,stacklevel=2)
-
-    def postParse( self, instring, loc, tokenlist ):
-        return list(map( string.upper, tokenlist ))
-
-
-class Combine(TokenConverter):
-    """Converter to concatenate all matching tokens to a single string.
-       By default, the matching patterns must also be contiguous in the input string;
-       this can be disabled by specifying C{'adjacent=False'} in the constructor.
-    """
-    def __init__( self, expr, joinString="", adjacent=True ):
-        super(Combine,self).__init__( expr )
-        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
-        if adjacent:
-            self.leaveWhitespace()
-        self.adjacent = adjacent
-        self.skipWhitespace = True
-        self.joinString = joinString
-        self.callPreparse = True
-
-    def ignore( self, other ):
-        if self.adjacent:
-            ParserElement.ignore(self, other)
-        else:
-            super( Combine, self).ignore( other )
-        return self
-
-    def postParse( self, instring, loc, tokenlist ):
-        retToks = tokenlist.copy()
-        del retToks[:]
-        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
-
-        if self.resultsName and len(retToks.keys())>0:
-            return [ retToks ]
-        else:
-            return retToks
-
-class Group(TokenConverter):
-    """Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions."""
-    def __init__( self, expr ):
-        super(Group,self).__init__( expr )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        return [ tokenlist ]
-
-class Dict(TokenConverter):
-    """Converter to return a repetitive expression as a list, but also as a dictionary.
-       Each element can also be referenced using the first token in the expression as its key.
-       Useful for tabular report scraping when the first column can be used as a item key.
-    """
-    def __init__( self, exprs ):
-        super(Dict,self).__init__( exprs )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        for i,tok in enumerate(tokenlist):
-            if len(tok) == 0:
-                continue
-            ikey = tok[0]
-            if isinstance(ikey,int):
-                ikey = _ustr(tok[0]).strip()
-            if len(tok)==1:
-                tokenlist[ikey] = _ParseResultsWithOffset("",i)
-            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
-                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
-            else:
-                dictvalue = tok.copy() #ParseResults(i)
-                del dictvalue[0]
-                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
-                else:
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
-
-        if self.resultsName:
-            return [ tokenlist ]
-        else:
-            return tokenlist
-
-
-class Suppress(TokenConverter):
-    """Converter for ignoring the results of a parsed expression."""
-    def postParse( self, instring, loc, tokenlist ):
-        return []
-
-    def suppress( self ):
-        return self
-
-
-class OnlyOnce(object):
-    """Wrapper for parse actions, to ensure they are only called once."""
-    def __init__(self, methodCall):
-        self.callable = _trim_arity(methodCall)
-        self.called = False
-    def __call__(self,s,l,t):
-        if not self.called:
-            results = self.callable(s,l,t)
-            self.called = True
-            return results
-        raise ParseException(s,l,"")
-    def reset(self):
-        self.called = False
-
-def traceParseAction(f):
-    """Decorator for debugging parse actions."""
-    f = _trim_arity(f)
-    def z(*paArgs):
-        thisFunc = f.func_name
-        s,l,t = paArgs[-3:]
-        if len(paArgs)>3:
-            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
-        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
-        try:
-            ret = f(*paArgs)
-        except Exception:
-            exc = sys.exc_info()[1]
-            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
-            raise
-        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
-        return ret
-    try:
-        z.__name__ = f.__name__
-    except AttributeError:
-        pass
-    return z
-
-#
-# global helpers
-#
-def delimitedList( expr, delim=",", combine=False ):
-    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
-       By default, the list elements and delimiters can have intervening whitespace, and
-       comments, but this can be overridden by passing C{combine=True} in the constructor.
-       If C{combine} is set to C{True}, the matching tokens are returned as a single token
-       string, with the delimiters included; otherwise, the matching tokens are returned
-       as a list of tokens, with the delimiters suppressed.
-    """
-    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
-    if combine:
-        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
-    else:
-        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
-
-def countedArray( expr, intExpr=None ):
-    """Helper to define a counted list of expressions.
-       This helper defines a pattern of the form::
-           integer expr expr expr...
-       where the leading integer tells how many expr expressions follow.
-       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
-    """
-    arrayExpr = Forward()
-    def countFieldParseAction(s,l,t):
-        n = t[0]
-        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
-        return []
-    if intExpr is None:
-        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
-    else:
-        intExpr = intExpr.copy()
-    intExpr.setName("arrayLen")
-    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
-    return ( intExpr + arrayExpr )
-
-def _flatten(L):
-    ret = []
-    for i in L:
-        if isinstance(i,list):
-            ret.extend(_flatten(i))
-        else:
-            ret.append(i)
-    return ret
-
-def matchPreviousLiteral(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousLiteral(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches a
-       previous literal, will also match the leading C{"1:1"} in C{"1:10"}.
-       If this is not desired, use C{matchPreviousExpr}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    def copyTokenToRepeater(s,l,t):
-        if t:
-            if len(t) == 1:
-                rep << t[0]
-            else:
-                # flatten t tokens
-                tflat = _flatten(t.asList())
-                rep << And( [ Literal(tt) for tt in tflat ] )
-        else:
-            rep << Empty()
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def matchPreviousExpr(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousExpr(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches by
-       expressions, will *not* match the leading C{"1:1"} in C{"1:10"};
-       the expressions are evaluated first, and then compared, so
-       C{"1"} is compared with C{"10"}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    e2 = expr.copy()
-    rep << e2
-    def copyTokenToRepeater(s,l,t):
-        matchTokens = _flatten(t.asList())
-        def mustMatchTheseTokens(s,l,t):
-            theseTokens = _flatten(t.asList())
-            if  theseTokens != matchTokens:
-                raise ParseException("",0,"")
-        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def _escapeRegexRangeChars(s):
-    #~  escape these chars: ^-]
-    for c in r"\^-]":
-        s = s.replace(c,_bslash+c)
-    s = s.replace("\n",r"\n")
-    s = s.replace("\t",r"\t")
-    return _ustr(s)
-
-def oneOf( strs, caseless=False, useRegex=True ):
-    """Helper to quickly define a set of alternative Literals, and makes sure to do
-       longest-first testing when there is a conflict, regardless of the input order,
-       but returns a C{L{MatchFirst}} for best performance.
-
-       Parameters:
-        - strs - a string of space-delimited literals, or a list of string literals
-        - caseless - (default=False) - treat all literals as caseless
-        - useRegex - (default=True) - as an optimization, will generate a Regex
-          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or
-          if creating a C{Regex} raises an exception)
-    """
-    if caseless:
-        isequal = ( lambda a,b: a.upper() == b.upper() )
-        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
-        parseElementClass = CaselessLiteral
-    else:
-        isequal = ( lambda a,b: a == b )
-        masks = ( lambda a,b: b.startswith(a) )
-        parseElementClass = Literal
-
-    if isinstance(strs,(list,tuple)):
-        symbols = list(strs[:])
-    elif isinstance(strs,basestring):
-        symbols = strs.split()
-    else:
-        warnings.warn("Invalid argument to oneOf, expected string or list",
-                SyntaxWarning, stacklevel=2)
-
-    i = 0
-    while i < len(symbols)-1:
-        cur = symbols[i]
-        for j,other in enumerate(symbols[i+1:]):
-            if ( isequal(other, cur) ):
-                del symbols[i+j+1]
-                break
-            elif ( masks(cur, other) ):
-                del symbols[i+j+1]
-                symbols.insert(i,other)
-                cur = other
-                break
-        else:
-            i += 1
-
-    if not caseless and useRegex:
-        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
-        try:
-            if len(symbols)==len("".join(symbols)):
-                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
-            else:
-                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
-        except:
-            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
-                    SyntaxWarning, stacklevel=2)
-
-
-    # last resort, just use MatchFirst
-    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
-
-def dictOf( key, value ):
-    """Helper to easily and clearly define a dictionary by specifying the respective patterns
-       for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens
-       in the proper order.  The key pattern can include delimiting markers or punctuation,
-       as long as they are suppressed, thereby leaving the significant key text.  The value
-       pattern can include named results, so that the C{Dict} results can include named token
-       fields.
-    """
-    return Dict( ZeroOrMore( Group ( key + value ) ) )
-
-def originalTextFor(expr, asString=True):
-    """Helper to return the original, untokenized text for a given expression.  Useful to
-       restore the parsed fields of an HTML start tag into the raw tag text itself, or to
-       revert separate tokens with intervening whitespace back to the original matching
-       input text. Simpler to use than the parse action C{L{keepOriginalText}}, and does not
-       require the inspect module to chase up the call stack.  By default, returns a 
-       string containing the original parsed text.  
-       
-       If the optional C{asString} argument is passed as C{False}, then the return value is a 
-       C{L{ParseResults}} containing any results names that were originally matched, and a 
-       single token containing the original matched text from the input string.  So if 
-       the expression passed to C{L{originalTextFor}} contains expressions with defined
-       results names, you must set C{asString} to C{False} if you want to preserve those
-       results name values."""
-    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
-    endlocMarker = locMarker.copy()
-    endlocMarker.callPreparse = False
-    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
-    if asString:
-        extractText = lambda s,l,t: s[t._original_start:t._original_end]
-    else:
-        def extractText(s,l,t):
-            del t[:]
-            t.insert(0, s[t._original_start:t._original_end])
-            del t["_original_start"]
-            del t["_original_end"]
-    matchExpr.setParseAction(extractText)
-    return matchExpr
-
-def ungroup(expr): 
-    """Helper to undo pyparsing's default grouping of And expressions, even
-       if all but one are non-empty."""
-    return TokenConverter(expr).setParseAction(lambda t:t[0])
-
-# convenience constants for positional expressions
-empty       = Empty().setName("empty")
-lineStart   = LineStart().setName("lineStart")
-lineEnd     = LineEnd().setName("lineEnd")
-stringStart = StringStart().setName("stringStart")
-stringEnd   = StringEnd().setName("stringEnd")
-
-_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
-_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
-_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
-_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
-_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
-_charRange = Group(_singleChar + Suppress("-") + _singleChar)
-_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
-
-_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
-
-def srange(s):
-    r"""Helper to easily define string ranges for use in Word construction.  Borrows
-       syntax from regexp '[]' string range definitions::
-          srange("[0-9]")   -> "0123456789"
-          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
-          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
-       The input string must be enclosed in []'s, and the returned string is the expanded
-       character set joined into a single string.
-       The values enclosed in the []'s may be::
-          a single character
-          an escaped character with a leading backslash (such as \- or \])
-          an escaped hex character with a leading '\x' (\x21, which is a '!' character) 
-            (\0x## is also supported for backwards compatibility) 
-          an escaped octal character with a leading '\0' (\041, which is a '!' character)
-          a range of any of the above, separated by a dash ('a-z', etc.)
-          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
-    """
-    try:
-        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
-    except:
-        return ""
-
-def matchOnlyAtCol(n):
-    """Helper method for defining parse actions that require matching at a specific
-       column in the input text.
-    """
-    def verifyCol(strg,locn,toks):
-        if col(locn,strg) != n:
-            raise ParseException(strg,locn,"matched token not at column %d" % n)
-    return verifyCol
-
-def replaceWith(replStr):
-    """Helper method for common parse actions that simply return a literal value.  Especially
-       useful when used with C{L{transformString<ParserElement.transformString>}()}.
-    """
-    def _replFunc(*args):
-        return [replStr]
-    return _replFunc
-
-def removeQuotes(s,l,t):
-    """Helper parse action for removing quotation marks from parsed quoted strings.
-       To use, add this parse action to quoted string using::
-         quotedString.setParseAction( removeQuotes )
-    """
-    return t[0][1:-1]
-
-def upcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to upper case."""
-    return [ tt.upper() for tt in map(_ustr,t) ]
-
-def downcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to lower case."""
-    return [ tt.lower() for tt in map(_ustr,t) ]
-
-def keepOriginalText(s,startLoc,t):
-    """DEPRECATED - use new helper method C{L{originalTextFor}}.
-       Helper parse action to preserve original parsed text,
-       overriding any nested parse actions."""
-    try:
-        endloc = getTokensEndLoc()
-    except ParseException:
-        raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
-    del t[:]
-    t += ParseResults(s[startLoc:endloc])
-    return t
-
-def getTokensEndLoc():
-    """Method to be called from within a parse action to determine the end
-       location of the parsed tokens."""
-    import inspect
-    fstack = inspect.stack()
-    try:
-        # search up the stack (through intervening argument normalizers) for correct calling routine
-        for f in fstack[2:]:
-            if f[3] == "_parseNoCache":
-                endloc = f[0].f_locals["loc"]
-                return endloc
-        else:
-            raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
-    finally:
-        del fstack
-
-def _makeTags(tagStr, xml):
-    """Internal helper to construct opening and closing tag expressions, given a tag name"""
-    if isinstance(tagStr,basestring):
-        resname = tagStr
-        tagStr = Keyword(tagStr, caseless=not xml)
-    else:
-        resname = tagStr.name
-
-    tagAttrName = Word(alphas,alphanums+"_-:")
-    if (xml):
-        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    else:
-        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
-        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
-                Optional( Suppress("=") + tagAttrValue ) ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    closeTag = Combine(_L("</") + tagStr + ">")
-
-    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
-    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
-    openTag.tag = resname
-    closeTag.tag = resname
-    return openTag, closeTag
-
-def makeHTMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
-    return _makeTags( tagStr, False )
-
-def makeXMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
-    return _makeTags( tagStr, True )
-
-def withAttribute(*args,**attrDict):
-    """Helper to create a validating parse action to be used with start tags created
-       with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag
-       with a required attribute value, to avoid false matches on common tags such as
-       C{<TD>} or C{<DIV>}.
-
-       Call C{withAttribute} with a series of attribute names and values. Specify the list
-       of filter attributes names and values as:
-        - keyword arguments, as in C{(align="right")}, or
-        - as an explicit dict with C{**} operator, when an attribute name is also a Python
-          reserved word, as in C{**{"class":"Customer", "align":"right"}}
-        - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
-       For attribute names with a namespace prefix, you must use the second form.  Attribute
-       names are matched insensitive to upper/lower case.
-
-       To verify that the attribute exists, but without specifying a value, pass
-       C{withAttribute.ANY_VALUE} as the value.
-       """
-    if args:
-        attrs = args[:]
-    else:
-        attrs = attrDict.items()
-    attrs = [(k,v) for k,v in attrs]
-    def pa(s,l,tokens):
-        for attrName,attrValue in attrs:
-            if attrName not in tokens:
-                raise ParseException(s,l,"no matching attribute " + attrName)
-            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
-                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
-                                            (attrName, tokens[attrName], attrValue))
-    return pa
-withAttribute.ANY_VALUE = object()
-
-opAssoc = _Constants()
-opAssoc.LEFT = object()
-opAssoc.RIGHT = object()
-
-def operatorPrecedence( baseExpr, opList ):
-    """Helper method for constructing grammars of expressions made up of
-       operators working in a precedence hierarchy.  Operators may be unary or
-       binary, left- or right-associative.  Parse actions can also be attached
-       to operator expressions.
-
-       Parameters:
-        - baseExpr - expression representing the most basic element for the nested
-        - opList - list of tuples, one for each operator precedence level in the
-          expression grammar; each tuple is of the form
-          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
-           - opExpr is the pyparsing expression for the operator;
-              may also be a string, which will be converted to a Literal;
-              if numTerms is 3, opExpr is a tuple of two expressions, for the
-              two operators separating the 3 terms
-           - numTerms is the number of terms for this operator (must
-              be 1, 2, or 3)
-           - rightLeftAssoc is the indicator whether the operator is
-              right or left associative, using the pyparsing-defined
-              constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.
-           - parseAction is the parse action to be associated with
-              expressions matching this operator expression (the
-              parse action tuple member may be omitted)
-    """
-    ret = Forward()
-    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
-    for i,operDef in enumerate(opList):
-        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
-        if arity == 3:
-            if opExpr is None or len(opExpr) != 2:
-                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
-            opExpr1, opExpr2 = opExpr
-        thisExpr = Forward()#.setName("expr%d" % i)
-        if rightLeftAssoc == opAssoc.LEFT:
-            if arity == 1:
-                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
-                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        elif rightLeftAssoc == opAssoc.RIGHT:
-            if arity == 1:
-                # try to avoid LR with this extra test
-                if not isinstance(opExpr, Optional):
-                    opExpr = Optional(opExpr)
-                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
-                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        else:
-            raise ValueError("operator must indicate right or left associativity")
-        if pa:
-            matchExpr.setParseAction( pa )
-        thisExpr << ( matchExpr | lastExpr )
-        lastExpr = thisExpr
-    ret << lastExpr
-    return ret
-
-dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
-sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
-quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
-unicodeString = Combine(_L('u') + quotedString.copy())
-
-def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()):
-    """Helper method for defining nested lists enclosed in opening and closing
-       delimiters ("(" and ")" are the default).
-
-       Parameters:
-        - opener - opening character for a nested list (default="("); can also be a pyparsing expression
-        - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
-        - content - expression for items within the nested lists (default=None)
-        - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
-
-       If an expression is not provided for the content argument, the nested
-       expression will capture all whitespace-delimited content between delimiters
-       as a list of separate values.
-
-       Use the C{ignoreExpr} argument to define expressions that may contain
-       opening or closing characters that should not be treated as opening
-       or closing characters for nesting, such as quotedString or a comment
-       expression.  Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}.
-       The default is L{quotedString}, but if no expressions are to be ignored,
-       then pass C{None} for this argument.
-    """
-    if opener == closer:
-        raise ValueError("opening and closing strings cannot be the same")
-    if content is None:
-        if isinstance(opener,basestring) and isinstance(closer,basestring):
-            if len(opener) == 1 and len(closer)==1:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr +
-                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
-                                ).setParseAction(lambda t:t[0].strip()))
-            else:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr + 
-                                    ~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-        else:
-            raise ValueError("opening and closing arguments must be strings if no content expression is given")
-    ret = Forward()
-    if ignoreExpr is not None:
-        ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
-    else:
-        ret << Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )
-    return ret
-
-def indentedBlock(blockStatementExpr, indentStack, indent=True):
-    """Helper method for defining space-delimited indentation blocks, such as
-       those used to define block statements in Python source code.
-
-       Parameters:
-        - blockStatementExpr - expression defining syntax of statement that
-            is repeated within the indented block
-        - indentStack - list created by caller to manage indentation stack
-            (multiple statementWithIndentedBlock expressions within a single grammar
-            should share a common indentStack)
-        - indent - boolean indicating whether block must be indented beyond the
-            the current level; set to False for block of left-most statements
-            (default=True)
-
-       A valid block must contain at least one C{blockStatement}.
-    """
-    def checkPeerIndent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if curCol != indentStack[-1]:
-            if curCol > indentStack[-1]:
-                raise ParseFatalException(s,l,"illegal nesting")
-            raise ParseException(s,l,"not a peer entry")
-
-    def checkSubIndent(s,l,t):
-        curCol = col(l,s)
-        if curCol > indentStack[-1]:
-            indentStack.append( curCol )
-        else:
-            raise ParseException(s,l,"not a subentry")
-
-    def checkUnindent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
-            raise ParseException(s,l,"not an unindent")
-        indentStack.pop()
-
-    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
-    INDENT = Empty() + Empty().setParseAction(checkSubIndent)
-    PEER   = Empty().setParseAction(checkPeerIndent)
-    UNDENT = Empty().setParseAction(checkUnindent)
-    if indent:
-        smExpr = Group( Optional(NL) +
-            #~ FollowedBy(blockStatementExpr) +
-            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
-    else:
-        smExpr = Group( Optional(NL) +
-            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
-    blockStatementExpr.ignore(_bslash + LineEnd())
-    return smExpr
-
-alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
-punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
-
-anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
-commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
-_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
-replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
-
-# it's easy to get these comment structures wrong - they're very common, so may as well make them available
-cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
-
-htmlComment = Regex(r"<!--[\s\S]*?-->")
-restOfLine = Regex(r".*").leaveWhitespace()
-dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
-cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
-
-javaStyleComment = cppStyleComment
-pythonStyleComment = Regex(r"#.*").setName("Python style comment")
-_noncomma = "".join( [ c for c in printables if c != "," ] )
-_commasepitem = Combine(OneOrMore(Word(_noncomma) +
-                                  Optional( Word(" \t") +
-                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
-commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList")
-
-
-if __name__ == "__main__":
-
-    def test( teststring ):
-        try:
-            tokens = simpleSQL.parseString( teststring )
-            tokenlist = tokens.asList()
-            print (teststring + "->"   + str(tokenlist))
-            print ("tokens = "         + str(tokens))
-            print ("tokens.columns = " + str(tokens.columns))
-            print ("tokens.tables = "  + str(tokens.tables))
-            print (tokens.asXML("SQL",True))
-        except ParseBaseException:
-            err = sys.exc_info()[1]
-            print (teststring + "->")
-            print (err.line)
-            print (" "*(err.column-1) + "^")
-            print (err)
-        print()
-
-    selectToken    = CaselessLiteral( "select" )
-    fromToken      = CaselessLiteral( "from" )
-
-    ident          = Word( alphas, alphanums + "_$" )
-    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
-    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
-    simpleSQL      = ( selectToken + \
-                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
-                     fromToken + \
-                     tableNameList.setResultsName( "tables" ) )
-
-    test( "SELECT * from XYZZY, ABC" )
-    test( "select * from SYS.XYZZY" )
-    test( "Select A from Sys.dual" )
-    test( "Select AA,BB,CC from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Xelect A, B, C from Sys.dual" )
-    test( "Select A, B, C frox Sys.dual" )
-    test( "Select" )
-    test( "Select ^^^ frox Sys.dual" )
-    test( "Select A, B, C from Sys.dual, Table2   " )
diff --git a/src/pyparsingClassDiagram.JPG b/src/pyparsingClassDiagram.JPG
deleted file mode 100644
index ef10424899c565f0f4e1067395c6a11a68728abb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

diff --git a/src/pyparsingClassDiagram.PNG b/src/pyparsingClassDiagram.PNG
deleted file mode 100644
index f59baaf3929638e74d5f21565f0bf95a1aca14a9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

diff --git a/src/pyparsing_py2.py b/src/pyparsing_py2.py
deleted file mode 100644
--- a/src/pyparsing_py2.py
+++ /dev/null
@@ -1,3740 +0,0 @@
-# module pyparsing.py
-#
-# Copyright (c) 2003-2011  Paul T. McGuire
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-#from __future__ import generators
-
-__doc__ = \
-"""
-pyparsing module - Classes and methods to define and execute parsing grammars
-
-The pyparsing module is an alternative approach to creating and executing simple grammars,
-vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
-don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
-provides a library of classes that you use to construct the grammar directly in Python.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form C{"<salutation>, <addressee>!"})::
-
-    from pyparsing import Word, alphas
-
-    # define grammar of a greeting
-    greet = Word( alphas ) + "," + Word( alphas ) + "!"
-
-    hello = "Hello, World!"
-    print hello, "->", greet.parseString( hello )
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the self-explanatory
-class names, and the use of '+', '|' and '^' operators.
-
-The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an
-object with named attributes.
-
-The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
- - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
- - quoted strings
- - embedded comments
-"""
-
-__version__ = "1.5.7"
-__versionTime__ = "3 August 2012 05:00"
-__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
-
-import string
-from weakref import ref as wkref
-import copy
-import sys
-import warnings
-import re
-import sre_constants
-#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
-
-__all__ = [
-'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
-'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
-'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
-'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
-'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
-'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
-'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
-'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
-'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
-'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
-'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
-'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
-'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
-'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
-'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
-'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
-'indentedBlock', 'originalTextFor', 'ungroup',
-]
-
-"""
-Detect if we are running version 3.X and make appropriate changes
-Robert A. Clark
-"""
-_PY3K = sys.version_info[0] > 2
-if _PY3K:
-    _MAX_INT = sys.maxsize
-    basestring = str
-    unichr = chr
-    _ustr = str
-else:
-    _MAX_INT = sys.maxint
-    range = xrange
-    set = lambda s : dict( [(c,0) for c in s] )
-
-    def _ustr(obj):
-        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
-           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
-           then < returns the unicode object | encodes it with the default encoding | ... >.
-        """
-        if isinstance(obj,unicode):
-            return obj
-
-        try:
-            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
-            # it won't break any existing code.
-            return str(obj)
-
-        except UnicodeEncodeError:
-            # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
-            # state that "The return value must be a string object". However, does a
-            # unicode object (being a subclass of basestring) count as a "string
-            # object"?
-            # If so, then return a unicode object:
-            return unicode(obj)
-            # Else encode it... but how? There are many choices... :)
-            # Replace unprintables with escape codes?
-            #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
-            # Replace unprintables with question marks?
-            #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
-            # ...
-
-# build list of single arg builtins, tolerant of Python version, that can be used as parse actions
-singleArgBuiltins = []
-import __builtin__
-for fname in "sum len sorted reversed list tuple set any all min max".split():
-    try:
-        singleArgBuiltins.append(getattr(__builtin__,fname))
-    except AttributeError:
-        continue
-
-def _xml_escape(data):
-    """Escape &, <, >, ", ', etc. in a string of data."""
-
-    # ampersand must be replaced first
-    from_symbols = '&><"\''
-    to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
-    for from_,to_ in zip(from_symbols, to_symbols):
-        data = data.replace(from_, to_)
-    return data
-
-class _Constants(object):
-    pass
-
-alphas     = string.ascii_lowercase + string.ascii_uppercase
-nums       = "0123456789"
-hexnums    = nums + "ABCDEFabcdef"
-alphanums  = alphas + nums
-_bslash    = chr(92)
-printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
-
-class ParseBaseException(Exception):
-    """base exception class for all parsing runtime exceptions"""
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, pstr, loc=0, msg=None, elem=None ):
-        self.loc = loc
-        if msg is None:
-            self.msg = pstr
-            self.pstr = ""
-        else:
-            self.msg = msg
-            self.pstr = pstr
-        self.parserElement = elem
-
-    def __getattr__( self, aname ):
-        """supported attributes by name are:
-            - lineno - returns the line number of the exception text
-            - col - returns the column number of the exception text
-            - line - returns the line containing the exception text
-        """
-        if( aname == "lineno" ):
-            return lineno( self.loc, self.pstr )
-        elif( aname in ("col", "column") ):
-            return col( self.loc, self.pstr )
-        elif( aname == "line" ):
-            return line( self.loc, self.pstr )
-        else:
-            raise AttributeError(aname)
-
-    def __str__( self ):
-        return "%s (at char %d), (line:%d, col:%d)" % \
-                ( self.msg, self.loc, self.lineno, self.column )
-    def __repr__( self ):
-        return _ustr(self)
-    def markInputline( self, markerString = ">!<" ):
-        """Extracts the exception line from the input string, and marks
-           the location of the exception with a special symbol.
-        """
-        line_str = self.line
-        line_column = self.column - 1
-        if markerString:
-            line_str = "".join( [line_str[:line_column],
-                                markerString, line_str[line_column:]])
-        return line_str.strip()
-    def __dir__(self):
-        return "loc msg pstr parserElement lineno col line " \
-               "markInputline __str__ __repr__".split()
-
-class ParseException(ParseBaseException):
-    """exception thrown when parse expressions don't match class;
-       supported attributes by name are:
-        - lineno - returns the line number of the exception text
-        - col - returns the column number of the exception text
-        - line - returns the line containing the exception text
-    """
-    pass
-
-class ParseFatalException(ParseBaseException):
-    """user-throwable exception thrown when inconsistent parse content
-       is found; stops all parsing immediately"""
-    pass
-
-class ParseSyntaxException(ParseFatalException):
-    """just like C{L{ParseFatalException}}, but thrown internally when an
-       C{L{ErrorStop<And._ErrorStop>}} ('-' operator) indicates that parsing is to stop immediately because
-       an unbacktrackable syntax error has been found"""
-    def __init__(self, pe):
-        super(ParseSyntaxException, self).__init__(
-                                    pe.pstr, pe.loc, pe.msg, pe.parserElement)
-
-#~ class ReparseException(ParseBaseException):
-    #~ """Experimental class - parse actions can raise this exception to cause
-       #~ pyparsing to reparse the input string:
-        #~ - with a modified input string, and/or
-        #~ - with a modified start location
-       #~ Set the values of the ReparseException in the constructor, and raise the
-       #~ exception in a parse action to cause pyparsing to use the new string/location.
-       #~ Setting the values as None causes no change to be made.
-       #~ """
-    #~ def __init_( self, newstring, restartLoc ):
-        #~ self.newParseText = newstring
-        #~ self.reparseLoc = restartLoc
-
-class RecursiveGrammarException(Exception):
-    """exception thrown by C{validate()} if the grammar could be improperly recursive"""
-    def __init__( self, parseElementList ):
-        self.parseElementTrace = parseElementList
-
-    def __str__( self ):
-        return "RecursiveGrammarException: %s" % self.parseElementTrace
-
-class _ParseResultsWithOffset(object):
-    def __init__(self,p1,p2):
-        self.tup = (p1,p2)
-    def __getitem__(self,i):
-        return self.tup[i]
-    def __repr__(self):
-        return repr(self.tup)
-    def setOffset(self,i):
-        self.tup = (self.tup[0],i)
-
-class ParseResults(object):
-    """Structured parse results, to provide multiple means of access to the parsed data:
-       - as a list (C{len(results)})
-       - by list index (C{results[0], results[1]}, etc.)
-       - by attribute (C{results.<resultsName>})
-       """
-    #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
-    def __new__(cls, toklist, name=None, asList=True, modal=True ):
-        if isinstance(toklist, cls):
-            return toklist
-        retobj = object.__new__(cls)
-        retobj.__doinit = True
-        return retobj
-
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, toklist, name=None, asList=True, modal=True, isinstance=isinstance ):
-        if self.__doinit:
-            self.__doinit = False
-            self.__name = None
-            self.__parent = None
-            self.__accumNames = {}
-            if isinstance(toklist, list):
-                self.__toklist = toklist[:]
-            else:
-                self.__toklist = [toklist]
-            self.__tokdict = dict()
-
-        if name is not None and name:
-            if not modal:
-                self.__accumNames[name] = 0
-            if isinstance(name,int):
-                name = _ustr(name) # will always return a str, but use _ustr for consistency
-            self.__name = name
-            if not toklist in (None,'',[]):
-                if isinstance(toklist,basestring):
-                    toklist = [ toklist ]
-                if asList:
-                    if isinstance(toklist,ParseResults):
-                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
-                    else:
-                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
-                    self[name].__name = name
-                else:
-                    try:
-                        self[name] = toklist[0]
-                    except (KeyError,TypeError,IndexError):
-                        self[name] = toklist
-
-    def __getitem__( self, i ):
-        if isinstance( i, (int,slice) ):
-            return self.__toklist[i]
-        else:
-            if i not in self.__accumNames:
-                return self.__tokdict[i][-1][0]
-            else:
-                return ParseResults([ v[0] for v in self.__tokdict[i] ])
-
-    def __setitem__( self, k, v, isinstance=isinstance ):
-        if isinstance(v,_ParseResultsWithOffset):
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
-            sub = v[0]
-        elif isinstance(k,int):
-            self.__toklist[k] = v
-            sub = v
-        else:
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
-            sub = v
-        if isinstance(sub,ParseResults):
-            sub.__parent = wkref(self)
-
-    def __delitem__( self, i ):
-        if isinstance(i,(int,slice)):
-            mylen = len( self.__toklist )
-            del self.__toklist[i]
-
-            # convert int to slice
-            if isinstance(i, int):
-                if i < 0:
-                    i += mylen
-                i = slice(i, i+1)
-            # get removed indices
-            removed = list(range(*i.indices(mylen)))
-            removed.reverse()
-            # fixup indices in token dictionary
-            for name in self.__tokdict:
-                occurrences = self.__tokdict[name]
-                for j in removed:
-                    for k, (value, position) in enumerate(occurrences):
-                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
-        else:
-            del self.__tokdict[i]
-
-    def __contains__( self, k ):
-        return k in self.__tokdict
-
-    def __len__( self ): return len( self.__toklist )
-    def __bool__(self): return len( self.__toklist ) > 0
-    __nonzero__ = __bool__
-    def __iter__( self ): return iter( self.__toklist )
-    def __reversed__( self ): return iter( self.__toklist[::-1] )
-    def keys( self ):
-        """Returns all named result keys."""
-        return self.__tokdict.keys()
-
-    def pop( self, index=-1 ):
-        """Removes and returns item at specified index (default=last).
-           Will work with either numeric indices or dict-key indicies."""
-        ret = self[index]
-        del self[index]
-        return ret
-
-    def get(self, key, defaultValue=None):
-        """Returns named result matching the given key, or if there is no
-           such name, then returns the given C{defaultValue} or C{None} if no
-           C{defaultValue} is specified."""
-        if key in self:
-            return self[key]
-        else:
-            return defaultValue
-
-    def insert( self, index, insStr ):
-        """Inserts new element at location index in the list of parsed tokens."""
-        self.__toklist.insert(index, insStr)
-        # fixup indices in token dictionary
-        for name in self.__tokdict:
-            occurrences = self.__tokdict[name]
-            for k, (value, position) in enumerate(occurrences):
-                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
-
-    def items( self ):
-        """Returns all named result keys and values as a list of tuples."""
-        return [(k,self[k]) for k in self.__tokdict]
-
-    def values( self ):
-        """Returns all named result values."""
-        return [ v[-1][0] for v in self.__tokdict.values() ]
-
-    def __getattr__( self, name ):
-        if True: #name not in self.__slots__:
-            if name in self.__tokdict:
-                if name not in self.__accumNames:
-                    return self.__tokdict[name][-1][0]
-                else:
-                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
-            else:
-                return ""
-        return None
-
-    def __add__( self, other ):
-        ret = self.copy()
-        ret += other
-        return ret
-
-    def __iadd__( self, other ):
-        if other.__tokdict:
-            offset = len(self.__toklist)
-            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
-            otheritems = other.__tokdict.items()
-            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
-                                for (k,vlist) in otheritems for v in vlist]
-            for k,v in otherdictitems:
-                self[k] = v
-                if isinstance(v[0],ParseResults):
-                    v[0].__parent = wkref(self)
-            
-        self.__toklist += other.__toklist
-        self.__accumNames.update( other.__accumNames )
-        return self
-
-    def __radd__(self, other):
-        if isinstance(other,int) and other == 0:
-            return self.copy()
-        
-    def __repr__( self ):
-        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
-
-    def __str__( self ):
-        out = []
-        for i in self.__toklist:
-            if isinstance(i, ParseResults):
-                out.append(_ustr(i))
-            else:
-                out.append(repr(i))
-        return '[' + ', '.join(out) + ']'
-
-    def _asStringList( self, sep='' ):
-        out = []
-        for item in self.__toklist:
-            if out and sep:
-                out.append(sep)
-            if isinstance( item, ParseResults ):
-                out += item._asStringList()
-            else:
-                out.append( _ustr(item) )
-        return out
-
-    def asList( self ):
-        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
-        out = []
-        for res in self.__toklist:
-            if isinstance(res,ParseResults):
-                out.append( res.asList() )
-            else:
-                out.append( res )
-        return out
-
-    def asDict( self ):
-        """Returns the named parse results as dictionary."""
-        return dict( self.items() )
-
-    def copy( self ):
-        """Returns a new copy of a C{ParseResults} object."""
-        ret = ParseResults( self.__toklist )
-        ret.__tokdict = self.__tokdict.copy()
-        ret.__parent = self.__parent
-        ret.__accumNames.update( self.__accumNames )
-        ret.__name = self.__name
-        return ret
-
-    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
-        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
-        nl = "\n"
-        out = []
-        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
-                                                            for v in vlist ] )
-        nextLevelIndent = indent + "  "
-
-        # collapse out indents if formatting is not desired
-        if not formatted:
-            indent = ""
-            nextLevelIndent = ""
-            nl = ""
-
-        selfTag = None
-        if doctag is not None:
-            selfTag = doctag
-        else:
-            if self.__name:
-                selfTag = self.__name
-
-        if not selfTag:
-            if namedItemsOnly:
-                return ""
-            else:
-                selfTag = "ITEM"
-
-        out += [ nl, indent, "<", selfTag, ">" ]
-
-        worklist = self.__toklist
-        for i,res in enumerate(worklist):
-            if isinstance(res,ParseResults):
-                if i in namedItems:
-                    out += [ res.asXML(namedItems[i],
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-                else:
-                    out += [ res.asXML(None,
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-            else:
-                # individual token, see if there is a name for it
-                resTag = None
-                if i in namedItems:
-                    resTag = namedItems[i]
-                if not resTag:
-                    if namedItemsOnly:
-                        continue
-                    else:
-                        resTag = "ITEM"
-                xmlBodyText = _xml_escape(_ustr(res))
-                out += [ nl, nextLevelIndent, "<", resTag, ">",
-                                                xmlBodyText,
-                                                "</", resTag, ">" ]
-
-        out += [ nl, indent, "</", selfTag, ">" ]
-        return "".join(out)
-
-    def __lookup(self,sub):
-        for k,vlist in self.__tokdict.items():
-            for v,loc in vlist:
-                if sub is v:
-                    return k
-        return None
-
-    def getName(self):
-        """Returns the results name for this token expression."""
-        if self.__name:
-            return self.__name
-        elif self.__parent:
-            par = self.__parent()
-            if par:
-                return par.__lookup(self)
-            else:
-                return None
-        elif (len(self) == 1 and
-               len(self.__tokdict) == 1 and
-               self.__tokdict.values()[0][0][1] in (0,-1)):
-            return self.__tokdict.keys()[0]
-        else:
-            return None
-
-    def dump(self,indent='',depth=0):
-        """Diagnostic method for listing out the contents of a C{ParseResults}.
-           Accepts an optional C{indent} argument so that this string can be embedded
-           in a nested display of other data."""
-        out = []
-        out.append( indent+_ustr(self.asList()) )
-        keys = self.items()
-        keys.sort()
-        for k,v in keys:
-            if out:
-                out.append('\n')
-            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
-            if isinstance(v,ParseResults):
-                if v.keys():
-                    out.append( v.dump(indent,depth+1) )
-                else:
-                    out.append(_ustr(v))
-            else:
-                out.append(_ustr(v))
-        return "".join(out)
-
-    # add support for pickle protocol
-    def __getstate__(self):
-        return ( self.__toklist,
-                 ( self.__tokdict.copy(),
-                   self.__parent is not None and self.__parent() or None,
-                   self.__accumNames,
-                   self.__name ) )
-
-    def __setstate__(self,state):
-        self.__toklist = state[0]
-        (self.__tokdict,
-         par,
-         inAccumNames,
-         self.__name) = state[1]
-        self.__accumNames = {}
-        self.__accumNames.update(inAccumNames)
-        if par is not None:
-            self.__parent = wkref(par)
-        else:
-            self.__parent = None
-
-    def __dir__(self):
-        return dir(super(ParseResults,self)) + list(self.keys())
-
-def col (loc,strg):
-    """Returns current column within a string, counting newlines as line separators.
-   The first column is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
-
-def lineno(loc,strg):
-    """Returns current line number within a string, counting newlines as line separators.
-   The first line is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return strg.count("\n",0,loc) + 1
-
-def line( loc, strg ):
-    """Returns the line of text containing loc within a string, counting newlines as line separators.
-       """
-    lastCR = strg.rfind("\n", 0, loc)
-    nextCR = strg.find("\n", loc)
-    if nextCR >= 0:
-        return strg[lastCR+1:nextCR]
-    else:
-        return strg[lastCR+1:]
-
-def _defaultStartDebugAction( instring, loc, expr ):
-    print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-
-def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
-    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
-
-def _defaultExceptionDebugAction( instring, loc, expr, exc ):
-    print ("Exception raised:" + _ustr(exc))
-
-def nullDebugAction(*args):
-    """'Do-nothing' debug action, to suppress debugging output during parsing."""
-    pass
-
-'decorator to trim function calls to match the arity of the target'
-def _trim_arity(func, maxargs=2):
-    if func in singleArgBuiltins:
-        return lambda s,l,t: func(t)
-    limit = [0]
-    def wrapper(*args):
-        while 1:
-            try:
-                return func(*args[limit[0]:])
-            except TypeError:
-                if limit[0] <= maxargs:
-                    limit[0] += 1
-                    continue
-                raise
-    return wrapper
-    
-class ParserElement(object):
-    """Abstract base level parser element class."""
-    DEFAULT_WHITE_CHARS = " \n\t\r"
-    verbose_stacktrace = False
-
-    def setDefaultWhitespaceChars( chars ):
-        """Overrides the default whitespace chars
-        """
-        ParserElement.DEFAULT_WHITE_CHARS = chars
-    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
-
-    def inlineLiteralsUsing(cls):
-        """
-        Set class to be used for inclusion of string literals into a parser.
-        """
-        ParserElement.literalStringClass = cls
-    inlineLiteralsUsing = staticmethod(inlineLiteralsUsing)
-
-    def __init__( self, savelist=False ):
-        self.parseAction = list()
-        self.failAction = None
-        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
-        self.strRepr = None
-        self.resultsName = None
-        self.saveAsList = savelist
-        self.skipWhitespace = True
-        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        self.copyDefaultWhiteChars = True
-        self.mayReturnEmpty = False # used when checking for left-recursion
-        self.keepTabs = False
-        self.ignoreExprs = list()
-        self.debug = False
-        self.streamlined = False
-        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
-        self.errmsg = ""
-        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
-        self.debugActions = ( None, None, None ) #custom debug actions
-        self.re = None
-        self.callPreparse = True # used to avoid redundant calls to preParse
-        self.callDuringTry = False
-
-    def copy( self ):
-        """Make a copy of this C{ParserElement}.  Useful for defining different parse actions
-           for the same parsing pattern, using copies of the original parse element."""
-        cpy = copy.copy( self )
-        cpy.parseAction = self.parseAction[:]
-        cpy.ignoreExprs = self.ignoreExprs[:]
-        if self.copyDefaultWhiteChars:
-            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        return cpy
-
-    def setName( self, name ):
-        """Define name for this expression, for use in debugging."""
-        self.name = name
-        self.errmsg = "Expected " + self.name
-        if hasattr(self,"exception"):
-            self.exception.msg = self.errmsg
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        """Define name for referencing matching tokens as a nested attribute
-           of the returned parse results.
-           NOTE: this returns a *copy* of the original C{ParserElement} object;
-           this is so that the client can define a basic element, such as an
-           integer, and reference it in multiple places with different names.
-           
-           You can also set results names using the abbreviated syntax,
-           C{expr("name")} in place of C{expr.setResultsName("name")} - 
-           see L{I{__call__}<__call__>}.
-        """
-        newself = self.copy()
-        if name.endswith("*"):
-            name = name[:-1]
-            listAllMatches=True
-        newself.resultsName = name
-        newself.modalResults = not listAllMatches
-        return newself
-
-    def setBreak(self,breakFlag = True):
-        """Method to invoke the Python pdb debugger when this element is
-           about to be parsed. Set C{breakFlag} to True to enable, False to
-           disable.
-        """
-        if breakFlag:
-            _parseMethod = self._parse
-            def breaker(instring, loc, doActions=True, callPreParse=True):
-                import pdb
-                pdb.set_trace()
-                return _parseMethod( instring, loc, doActions, callPreParse )
-            breaker._originalParseMethod = _parseMethod
-            self._parse = breaker
-        else:
-            if hasattr(self._parse,"_originalParseMethod"):
-                self._parse = self._parse._originalParseMethod
-        return self
-
-    def setParseAction( self, *fns, **kwargs ):
-        """Define action to perform when successfully matching parse element definition.
-           Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
-           C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
-            - s   = the original string being parsed (see note below)
-            - loc = the location of the matching substring
-            - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object
-           If the functions in fns modify the tokens, they can return them as the return
-           value from fn, and the modified list of tokens will replace the original.
-           Otherwise, fn does not need to return any value.
-
-           Note: the default parsing behavior is to expand tabs in the input string
-           before starting the parsing process.  See L{I{parseString}<parseString>} for more information
-           on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-           consistent view of the parsed string, the parse location, and line and column
-           positions within the parsed string.
-           """
-        self.parseAction = list(map(_trim_arity, list(fns)))
-        self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def addParseAction( self, *fns, **kwargs ):
-        """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
-        self.parseAction += list(map(_trim_arity, list(fns)))
-        self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def setFailAction( self, fn ):
-        """Define action to perform if parsing fails at this expression.
-           Fail acton fn is a callable function that takes the arguments
-           C{fn(s,loc,expr,err)} where:
-            - s = string being parsed
-            - loc = location where expression match was attempted and failed
-            - expr = the parse expression that failed
-            - err = the exception thrown
-           The function returns no value.  It may throw C{L{ParseFatalException}}
-           if it is desired to stop parsing immediately."""
-        self.failAction = fn
-        return self
-
-    def _skipIgnorables( self, instring, loc ):
-        exprsFound = True
-        while exprsFound:
-            exprsFound = False
-            for e in self.ignoreExprs:
-                try:
-                    while 1:
-                        loc,dummy = e._parse( instring, loc )
-                        exprsFound = True
-                except ParseException:
-                    pass
-        return loc
-
-    def preParse( self, instring, loc ):
-        if self.ignoreExprs:
-            loc = self._skipIgnorables( instring, loc )
-
-        if self.skipWhitespace:
-            wt = self.whiteChars
-            instrlen = len(instring)
-            while loc < instrlen and instring[loc] in wt:
-                loc += 1
-
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        return loc, []
-
-    def postParse( self, instring, loc, tokenlist ):
-        return tokenlist
-
-    #~ @profile
-    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
-        debugging = ( self.debug ) #and doActions )
-
-        if debugging or self.failAction:
-            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-            if (self.debugActions[0] ):
-                self.debugActions[0]( instring, loc, self )
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            try:
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            except ParseBaseException:
-                #~ print ("Exception raised:", err)
-                err = None
-                if self.debugActions[2]:
-                    err = sys.exc_info()[1]
-                    self.debugActions[2]( instring, tokensStart, self, err )
-                if self.failAction:
-                    if err is None:
-                        err = sys.exc_info()[1]
-                    self.failAction( instring, tokensStart, self, err )
-                raise
-        else:
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            if self.mayIndexError or loc >= len(instring):
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            else:
-                loc,tokens = self.parseImpl( instring, preloc, doActions )
-
-        tokens = self.postParse( instring, loc, tokens )
-
-        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
-        if self.parseAction and (doActions or self.callDuringTry):
-            if debugging:
-                try:
-                    for fn in self.parseAction:
-                        tokens = fn( instring, tokensStart, retTokens )
-                        if tokens is not None:
-                            retTokens = ParseResults( tokens,
-                                                      self.resultsName,
-                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                      modal=self.modalResults )
-                except ParseBaseException:
-                    #~ print "Exception raised in user parse action:", err
-                    if (self.debugActions[2] ):
-                        err = sys.exc_info()[1]
-                        self.debugActions[2]( instring, tokensStart, self, err )
-                    raise
-            else:
-                for fn in self.parseAction:
-                    tokens = fn( instring, tokensStart, retTokens )
-                    if tokens is not None:
-                        retTokens = ParseResults( tokens,
-                                                  self.resultsName,
-                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                  modal=self.modalResults )
-
-        if debugging:
-            #~ print ("Matched",self,"->",retTokens.asList())
-            if (self.debugActions[1] ):
-                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
-
-        return loc, retTokens
-
-    def tryParse( self, instring, loc ):
-        try:
-            return self._parse( instring, loc, doActions=False )[0]
-        except ParseFatalException:
-            raise ParseException( instring, loc, self.errmsg, self)
-
-    # this method gets repeatedly called during backtracking with the same arguments -
-    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
-    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
-        lookup = (self,instring,loc,callPreParse,doActions)
-        if lookup in ParserElement._exprArgCache:
-            value = ParserElement._exprArgCache[ lookup ]
-            if isinstance(value, Exception):
-                raise value
-            return (value[0],value[1].copy())
-        else:
-            try:
-                value = self._parseNoCache( instring, loc, doActions, callPreParse )
-                ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
-                return value
-            except ParseBaseException:
-                pe = sys.exc_info()[1]
-                ParserElement._exprArgCache[ lookup ] = pe
-                raise
-
-    _parse = _parseNoCache
-
-    # argument cache for optimizing repeated calls when backtracking through recursive expressions
-    _exprArgCache = {}
-    def resetCache():
-        ParserElement._exprArgCache.clear()
-    resetCache = staticmethod(resetCache)
-
-    _packratEnabled = False
-    def enablePackrat():
-        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
-           Repeated parse attempts at the same string location (which happens
-           often in many complex grammars) can immediately return a cached value,
-           instead of re-executing parsing/validating code.  Memoizing is done of
-           both valid results and parsing exceptions.
-
-           This speedup may break existing programs that use parse actions that
-           have side-effects.  For this reason, packrat parsing is disabled when
-           you first import pyparsing.  To activate the packrat feature, your
-           program must call the class method C{ParserElement.enablePackrat()}.  If
-           your program uses C{psyco} to "compile as you go", you must call
-           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,
-           Python will crash.  For best results, call C{enablePackrat()} immediately
-           after importing pyparsing.
-        """
-        if not ParserElement._packratEnabled:
-            ParserElement._packratEnabled = True
-            ParserElement._parse = ParserElement._parseCache
-    enablePackrat = staticmethod(enablePackrat)
-
-    def parseString( self, instring, parseAll=False ):
-        """Execute the parse expression with the given string.
-           This is the main interface to the client code, once the complete
-           expression has been built.
-
-           If you want the grammar to require that the entire input string be
-           successfully parsed, then set C{parseAll} to True (equivalent to ending
-           the grammar with C{L{StringEnd()}}).
-
-           Note: C{parseString} implicitly calls C{expandtabs()} on the input string,
-           in order to report proper column numbers in parse actions.
-           If the input string contains tabs and
-           the grammar uses parse actions that use the C{loc} argument to index into the
-           string being parsed, you can ensure you have a consistent view of the input
-           string by:
-            - calling C{parseWithTabs} on your grammar before calling C{parseString}
-              (see L{I{parseWithTabs}<parseWithTabs>})
-            - define your parse action using the full C{(s,loc,toks)} signature, and
-              reference the input string using the parse action's C{s} argument
-            - explictly expand the tabs in your input string before calling
-              C{parseString}
-        """
-        ParserElement.resetCache()
-        if not self.streamlined:
-            self.streamline()
-            #~ self.saveAsList = True
-        for e in self.ignoreExprs:
-            e.streamline()
-        if not self.keepTabs:
-            instring = instring.expandtabs()
-        try:
-            loc, tokens = self._parse( instring, 0 )
-            if parseAll:
-                loc = self.preParse( instring, loc )
-                se = Empty() + StringEnd()
-                se._parse( instring, loc )
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-        else:
-            return tokens
-
-    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
-        """Scan the input string for expression matches.  Each match will return the
-           matching tokens, start location, and end location.  May be called with optional
-           C{maxMatches} argument, to clip scanning after 'n' matches are found.  If
-           C{overlap} is specified, then overlapping matches will be reported.
-
-           Note that the start and end locations are reported relative to the string
-           being parsed.  See L{I{parseString}<parseString>} for more information on parsing
-           strings with embedded tabs."""
-        if not self.streamlined:
-            self.streamline()
-        for e in self.ignoreExprs:
-            e.streamline()
-
-        if not self.keepTabs:
-            instring = _ustr(instring).expandtabs()
-        instrlen = len(instring)
-        loc = 0
-        preparseFn = self.preParse
-        parseFn = self._parse
-        ParserElement.resetCache()
-        matches = 0
-        try:
-            while loc <= instrlen and matches < maxMatches:
-                try:
-                    preloc = preparseFn( instring, loc )
-                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
-                except ParseException:
-                    loc = preloc+1
-                else:
-                    if nextLoc > loc:
-                        matches += 1
-                        yield tokens, preloc, nextLoc
-                        if overlap:
-                            nextloc = preparseFn( instring, loc )
-                            if nextloc > loc:
-                                loc = nextLoc
-                            else:
-                                loc += 1
-                        else:
-                            loc = nextLoc
-                    else:
-                        loc = preloc+1
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def transformString( self, instring ):
-        """Extension to C{L{scanString}}, to modify matching text with modified tokens that may
-           be returned from a parse action.  To use C{transformString}, define a grammar and
-           attach a parse action to it that modifies the returned token list.
-           Invoking C{transformString()} on a target string will then scan for matches,
-           and replace the matched text patterns according to the logic in the parse
-           action.  C{transformString()} returns the resulting transformed string."""
-        out = []
-        lastE = 0
-        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
-        # keep string locs straight between transformString and scanString
-        self.keepTabs = True
-        try:
-            for t,s,e in self.scanString( instring ):
-                out.append( instring[lastE:s] )
-                if t:
-                    if isinstance(t,ParseResults):
-                        out += t.asList()
-                    elif isinstance(t,list):
-                        out += t
-                    else:
-                        out.append(t)
-                lastE = e
-            out.append(instring[lastE:])
-            out = [o for o in out if o]
-            return "".join(map(_ustr,_flatten(out)))
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def searchString( self, instring, maxMatches=_MAX_INT ):
-        """Another extension to C{L{scanString}}, simplifying the access to the tokens found
-           to match the given parse expression.  May be called with optional
-           C{maxMatches} argument, to clip searching after 'n' matches are found.
-        """
-        try:
-            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
-        except ParseBaseException:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                exc = sys.exc_info()[1]
-                raise exc
-
-    def __add__(self, other ):
-        """Implementation of + operator - returns C{L{And}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, other ] )
-
-    def __radd__(self, other ):
-        """Implementation of + operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other + self
-
-    def __sub__(self, other):
-        """Implementation of - operator, returns C{L{And}} with error stop"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, And._ErrorStop(), other ] )
-
-    def __rsub__(self, other ):
-        """Implementation of - operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other - self
-
-    def __mul__(self,other):
-        """Implementation of * operator, allows use of C{expr * 3} in place of
-           C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer
-           tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples
-           may also include C{None} as in:
-            - C{expr*(n,None)} or C{expr*(n,)} is equivalent
-              to C{expr*n + L{ZeroOrMore}(expr)}
-              (read as "at least n instances of C{expr}")
-            - C{expr*(None,n)} is equivalent to C{expr*(0,n)}
-              (read as "0 to n instances of C{expr}")
-            - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}
-            - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}
-
-           Note that C{expr*(None,n)} does not raise an exception if
-           more than n exprs exist in the input stream; that is,
-           C{expr*(None,n)} does not enforce a maximum number of expr
-           occurrences.  If this behavior is desired, then write
-           C{expr*(None,n) + ~expr}
-
-        """
-        if isinstance(other,int):
-            minElements, optElements = other,0
-        elif isinstance(other,tuple):
-            other = (other + (None, None))[:2]
-            if other[0] is None:
-                other = (0, other[1])
-            if isinstance(other[0],int) and other[1] is None:
-                if other[0] == 0:
-                    return ZeroOrMore(self)
-                if other[0] == 1:
-                    return OneOrMore(self)
-                else:
-                    return self*other[0] + ZeroOrMore(self)
-            elif isinstance(other[0],int) and isinstance(other[1],int):
-                minElements, optElements = other
-                optElements -= minElements
-            else:
-                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
-        else:
-            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
-
-        if minElements < 0:
-            raise ValueError("cannot multiply ParserElement by negative value")
-        if optElements < 0:
-            raise ValueError("second tuple value must be greater or equal to first tuple value")
-        if minElements == optElements == 0:
-            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
-
-        if (optElements):
-            def makeOptionalList(n):
-                if n>1:
-                    return Optional(self + makeOptionalList(n-1))
-                else:
-                    return Optional(self)
-            if minElements:
-                if minElements == 1:
-                    ret = self + makeOptionalList(optElements)
-                else:
-                    ret = And([self]*minElements) + makeOptionalList(optElements)
-            else:
-                ret = makeOptionalList(optElements)
-        else:
-            if minElements == 1:
-                ret = self
-            else:
-                ret = And([self]*minElements)
-        return ret
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-
-    def __or__(self, other ):
-        """Implementation of | operator - returns C{L{MatchFirst}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return MatchFirst( [ self, other ] )
-
-    def __ror__(self, other ):
-        """Implementation of | operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other | self
-
-    def __xor__(self, other ):
-        """Implementation of ^ operator - returns C{L{Or}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Or( [ self, other ] )
-
-    def __rxor__(self, other ):
-        """Implementation of ^ operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other ^ self
-
-    def __and__(self, other ):
-        """Implementation of & operator - returns C{L{Each}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Each( [ self, other ] )
-
-    def __rand__(self, other ):
-        """Implementation of & operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other & self
-
-    def __invert__( self ):
-        """Implementation of ~ operator - returns C{L{NotAny}}"""
-        return NotAny( self )
-
-    def __call__(self, name):
-        """Shortcut for C{L{setResultsName}}, with C{listAllMatches=default}::
-             userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
-           could be written as::
-             userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
-             
-           If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be
-           passed as C{True}.
-           """
-        return self.setResultsName(name)
-
-    def suppress( self ):
-        """Suppresses the output of this C{ParserElement}; useful to keep punctuation from
-           cluttering up returned output.
-        """
-        return Suppress( self )
-
-    def leaveWhitespace( self ):
-        """Disables the skipping of whitespace before matching the characters in the
-           C{ParserElement}'s defined pattern.  This is normally only used internally by
-           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
-        """
-        self.skipWhitespace = False
-        return self
-
-    def setWhitespaceChars( self, chars ):
-        """Overrides the default whitespace chars
-        """
-        self.skipWhitespace = True
-        self.whiteChars = chars
-        self.copyDefaultWhiteChars = False
-        return self
-
-    def parseWithTabs( self ):
-        """Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string.
-           Must be called before C{parseString} when the input grammar contains elements that
-           match C{<TAB>} characters."""
-        self.keepTabs = True
-        return self
-
-    def ignore( self, other ):
-        """Define expression to be ignored (e.g., comments) while doing pattern
-           matching; may be called repeatedly, to define multiple comment or other
-           ignorable patterns.
-        """
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                self.ignoreExprs.append( other.copy() )
-        else:
-            self.ignoreExprs.append( Suppress( other.copy() ) )
-        return self
-
-    def setDebugActions( self, startAction, successAction, exceptionAction ):
-        """Enable display of debugging messages while doing pattern matching."""
-        self.debugActions = (startAction or _defaultStartDebugAction,
-                             successAction or _defaultSuccessDebugAction,
-                             exceptionAction or _defaultExceptionDebugAction)
-        self.debug = True
-        return self
-
-    def setDebug( self, flag=True ):
-        """Enable display of debugging messages while doing pattern matching.
-           Set C{flag} to True to enable, False to disable."""
-        if flag:
-            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
-        else:
-            self.debug = False
-        return self
-
-    def __str__( self ):
-        return self.name
-
-    def __repr__( self ):
-        return _ustr(self)
-
-    def streamline( self ):
-        self.streamlined = True
-        self.strRepr = None
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        pass
-
-    def validate( self, validateTrace=[] ):
-        """Check defined expressions for valid structure, check for infinite recursive definitions."""
-        self.checkRecursion( [] )
-
-    def parseFile( self, file_or_filename, parseAll=False ):
-        """Execute the parse expression on the given file or filename.
-           If a filename is specified (instead of a file object),
-           the entire file is opened, read, and closed before parsing.
-        """
-        try:
-            file_contents = file_or_filename.read()
-        except AttributeError:
-            f = open(file_or_filename, "r")
-            file_contents = f.read()
-            f.close()
-        try:
-            return self.parseString(file_contents, parseAll)
-        except ParseBaseException:
-            # catch and re-raise exception from here, clears out pyparsing internal stack trace
-            exc = sys.exc_info()[1]
-            raise exc
-
-    def getException(self):
-        return ParseException("",0,self.errmsg,self)
-
-    def __getattr__(self,aname):
-        if aname == "myException":
-            self.myException = ret = self.getException();
-            return ret;
-        else:
-            raise AttributeError("no such attribute " + aname)
-
-    def __eq__(self,other):
-        if isinstance(other, ParserElement):
-            return self is other or self.__dict__ == other.__dict__
-        elif isinstance(other, basestring):
-            try:
-                self.parseString(_ustr(other), parseAll=True)
-                return True
-            except ParseBaseException:
-                return False
-        else:
-            return super(ParserElement,self)==other
-
-    def __ne__(self,other):
-        return not (self == other)
-
-    def __hash__(self):
-        return hash(id(self))
-
-    def __req__(self,other):
-        return self == other
-
-    def __rne__(self,other):
-        return not (self == other)
-
-
-class Token(ParserElement):
-    """Abstract C{ParserElement} subclass, for defining atomic matching patterns."""
-    def __init__( self ):
-        super(Token,self).__init__( savelist=False )
-
-    def setName(self, name):
-        s = super(Token,self).setName(name)
-        self.errmsg = "Expected " + self.name
-        return s
-
-
-class Empty(Token):
-    """An empty token, will always match."""
-    def __init__( self ):
-        super(Empty,self).__init__()
-        self.name = "Empty"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-
-class NoMatch(Token):
-    """A token that will never match."""
-    def __init__( self ):
-        super(NoMatch,self).__init__()
-        self.name = "NoMatch"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.errmsg = "Unmatchable token"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-
-class Literal(Token):
-    """Token to exactly match a specified string."""
-    def __init__( self, matchString ):
-        super(Literal,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Literal; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-            self.__class__ = Empty
-        self.name = '"%s"' % _ustr(self.match)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-
-    # Performance tuning: this routine gets called a *lot*
-    # if this is a single character match string  and the first character matches,
-    # short-circuit as quickly as possible, and avoid calling startswith
-    #~ @profile
-    def parseImpl( self, instring, loc, doActions=True ):
-        if (instring[loc] == self.firstMatchChar and
-            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
-            return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-_L = Literal
-ParserElement.literalStringClass = Literal
-
-class Keyword(Token):
-    """Token to exactly match a specified string as a keyword, that is, it must be
-       immediately followed by a non-keyword character.  Compare with C{L{Literal}}::
-         Literal("if") will match the leading C{'if'} in C{'ifAndOnlyIf'}.
-         Keyword("if") will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}
-       Accepts two optional constructor arguments in addition to the keyword string:
-       C{identChars} is a string of characters that would be valid identifier characters,
-       defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive
-       matching, default is C{False}.
-    """
-    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
-
-    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
-        super(Keyword,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Keyword; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-        self.name = '"%s"' % self.match
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-        self.caseless = caseless
-        if caseless:
-            self.caselessmatch = matchString.upper()
-            identChars = identChars.upper()
-        self.identChars = set(identChars)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.caseless:
-            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
-                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        else:
-            if (instring[loc] == self.firstMatchChar and
-                (self.matchLen==1 or instring.startswith(self.match,loc)) and
-                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
-                (loc == 0 or instring[loc-1] not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-    def copy(self):
-        c = super(Keyword,self).copy()
-        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
-        return c
-
-    def setDefaultKeywordChars( chars ):
-        """Overrides the default Keyword chars
-        """
-        Keyword.DEFAULT_KEYWORD_CHARS = chars
-    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
-
-class CaselessLiteral(Literal):
-    """Token to match a specified string, ignoring case of letters.
-       Note: the matched results will always be in the case of the given
-       match string, NOT the case of the input text.
-    """
-    def __init__( self, matchString ):
-        super(CaselessLiteral,self).__init__( matchString.upper() )
-        # Preserve the defining literal.
-        self.returnString = matchString
-        self.name = "'%s'" % self.returnString
-        self.errmsg = "Expected " + self.name
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[ loc:loc+self.matchLen ].upper() == self.match:
-            return loc+self.matchLen, self.returnString
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class CaselessKeyword(Keyword):
-    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
-        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
-            return loc+self.matchLen, self.match
-        #~ raise ParseException( instring, loc, self.errmsg )
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class Word(Token):
-    """Token for matching words composed of allowed character sets.
-       Defined with string containing all allowed initial characters,
-       an optional string containing allowed body characters (if omitted,
-       defaults to the initial character set), and an optional minimum,
-       maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction. An optional
-       C{exclude} parameter can list characters that might be found in 
-       the input C{bodyChars} string; useful to define a word of all printables
-       except for one or two characters, for instance.
-    """
-    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
-        super(Word,self).__init__()
-        if excludeChars:
-            initChars = ''.join([c for c in initChars if c not in excludeChars])
-            if bodyChars:
-                bodyChars = ''.join([c for c in bodyChars if c not in excludeChars])
-        self.initCharsOrig = initChars
-        self.initChars = set(initChars)
-        if bodyChars :
-            self.bodyCharsOrig = bodyChars
-            self.bodyChars = set(bodyChars)
-        else:
-            self.bodyCharsOrig = initChars
-            self.bodyChars = set(initChars)
-
-        self.maxSpecified = max > 0
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.asKeyword = asKeyword
-
-        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
-            if self.bodyCharsOrig == self.initCharsOrig:
-                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
-            elif len(self.bodyCharsOrig) == 1:
-                self.reString = "%s[%s]*" % \
-                                      (re.escape(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            else:
-                self.reString = "[%s][%s]*" % \
-                                      (_escapeRegexRangeChars(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            if self.asKeyword:
-                self.reString = r"\b"+self.reString+r"\b"
-            try:
-                self.re = re.compile( self.reString )
-            except:
-                self.re = None
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.re:
-            result = self.re.match(instring,loc)
-            if not result:
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-
-            loc = result.end()
-            return loc, result.group()
-
-        if not(instring[ loc ] in self.initChars):
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        start = loc
-        loc += 1
-        instrlen = len(instring)
-        bodychars = self.bodyChars
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, instrlen )
-        while loc < maxloc and instring[loc] in bodychars:
-            loc += 1
-
-        throwException = False
-        if loc - start < self.minLen:
-            throwException = True
-        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
-            throwException = True
-        if self.asKeyword:
-            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
-                throwException = True
-
-        if throwException:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(Word,self).__str__()
-        except:
-            pass
-
-
-        if self.strRepr is None:
-
-            def charsAsStr(s):
-                if len(s)>4:
-                    return s[:4]+"..."
-                else:
-                    return s
-
-            if ( self.initCharsOrig != self.bodyCharsOrig ):
-                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
-            else:
-                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
-
-        return self.strRepr
-
-
-class Regex(Token):
-    """Token for matching strings that match a given regular expression.
-       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
-    """
-    compiledREtype = type(re.compile("[A-Z]"))
-    def __init__( self, pattern, flags=0):
-        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""
-        super(Regex,self).__init__()
-
-        if isinstance(pattern, basestring):
-            if len(pattern) == 0:
-                warnings.warn("null string passed to Regex; use Empty() instead",
-                        SyntaxWarning, stacklevel=2)
-
-            self.pattern = pattern
-            self.flags = flags
-
-            try:
-                self.re = re.compile(self.pattern, self.flags)
-                self.reString = self.pattern
-            except sre_constants.error:
-                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
-                    SyntaxWarning, stacklevel=2)
-                raise
-
-        elif isinstance(pattern, Regex.compiledREtype):
-            self.re = pattern
-            self.pattern = \
-            self.reString = str(pattern)
-            self.flags = flags
-            
-        else:
-            raise ValueError("Regex may only be constructed with a string or a compiled RE object")
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = self.re.match(instring,loc)
-        if not result:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        loc = result.end()
-        d = result.groupdict()
-        ret = ParseResults(result.group())
-        if d:
-            for k in d:
-                ret[k] = d[k]
-        return loc,ret
-
-    def __str__( self ):
-        try:
-            return super(Regex,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "Re:(%s)" % repr(self.pattern)
-
-        return self.strRepr
-
-
-class QuotedString(Token):
-    """Token for matching strings that are delimited by quoting characters.
-    """
-    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
-        """
-           Defined with the following parameters:
-            - quoteChar - string of one or more characters defining the quote delimiting string
-            - escChar - character to escape quotes, typically backslash (default=None)
-            - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
-            - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})
-            - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})
-            - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)
-        """
-        super(QuotedString,self).__init__()
-
-        # remove white space from quote chars - wont work anyway
-        quoteChar = quoteChar.strip()
-        if len(quoteChar) == 0:
-            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-            raise SyntaxError()
-
-        if endQuoteChar is None:
-            endQuoteChar = quoteChar
-        else:
-            endQuoteChar = endQuoteChar.strip()
-            if len(endQuoteChar) == 0:
-                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-                raise SyntaxError()
-
-        self.quoteChar = quoteChar
-        self.quoteCharLen = len(quoteChar)
-        self.firstQuoteChar = quoteChar[0]
-        self.endQuoteChar = endQuoteChar
-        self.endQuoteCharLen = len(endQuoteChar)
-        self.escChar = escChar
-        self.escQuote = escQuote
-        self.unquoteResults = unquoteResults
-
-        if multiline:
-            self.flags = re.MULTILINE | re.DOTALL
-            self.pattern = r'%s(?:[^%s%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        else:
-            self.flags = 0
-            self.pattern = r'%s(?:[^%s\n\r%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        if len(self.endQuoteChar) > 1:
-            self.pattern += (
-                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
-                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
-                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
-                )
-        if escQuote:
-            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
-        if escChar:
-            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
-            charset = ''.join(set(self.quoteChar[0]+self.endQuoteChar[0])).replace('^',r'\^').replace('-',r'\-')
-            self.escCharReplacePattern = re.escape(self.escChar)+("([%s])" % charset)
-        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
-
-        try:
-            self.re = re.compile(self.pattern, self.flags)
-            self.reString = self.pattern
-        except sre_constants.error:
-            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
-                SyntaxWarning, stacklevel=2)
-            raise
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
-        if not result:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        loc = result.end()
-        ret = result.group()
-
-        if self.unquoteResults:
-
-            # strip off quotes
-            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
-
-            if isinstance(ret,basestring):
-                # replace escaped characters
-                if self.escChar:
-                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
-
-                # replace escaped quotes
-                if self.escQuote:
-                    ret = ret.replace(self.escQuote, self.endQuoteChar)
-
-        return loc, ret
-
-    def __str__( self ):
-        try:
-            return super(QuotedString,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
-
-        return self.strRepr
-
-
-class CharsNotIn(Token):
-    """Token for matching words composed of characters *not* in a given set.
-       Defined with string containing all disallowed characters, and an optional
-       minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction.
-    """
-    def __init__( self, notChars, min=1, max=0, exact=0 ):
-        super(CharsNotIn,self).__init__()
-        self.skipWhitespace = False
-        self.notChars = notChars
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = ( self.minLen == 0 )
-        self.mayIndexError = False
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[loc] in self.notChars:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        start = loc
-        loc += 1
-        notchars = self.notChars
-        maxlen = min( start+self.maxLen, len(instring) )
-        while loc < maxlen and \
-              (instring[loc] not in notchars):
-            loc += 1
-
-        if loc - start < self.minLen:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(CharsNotIn, self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            if len(self.notChars) > 4:
-                self.strRepr = "!W:(%s...)" % self.notChars[:4]
-            else:
-                self.strRepr = "!W:(%s)" % self.notChars
-
-        return self.strRepr
-
-class White(Token):
-    """Special matching class for matching whitespace.  Normally, whitespace is ignored
-       by pyparsing grammars.  This class is included when some whitespace structures
-       are significant.  Define with a string containing the whitespace characters to be
-       matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,
-       as defined for the C{L{Word}} class."""
-    whiteStrs = {
-        " " : "<SPC>",
-        "\t": "<TAB>",
-        "\n": "<LF>",
-        "\r": "<CR>",
-        "\f": "<FF>",
-        }
-    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
-        super(White,self).__init__()
-        self.matchWhite = ws
-        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
-        #~ self.leaveWhitespace()
-        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
-        self.mayReturnEmpty = True
-        self.errmsg = "Expected " + self.name
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not(instring[ loc ] in self.matchWhite):
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        start = loc
-        loc += 1
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, len(instring) )
-        while loc < maxloc and instring[loc] in self.matchWhite:
-            loc += 1
-
-        if loc - start < self.minLen:
-            #~ raise ParseException( instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-        return loc, instring[start:loc]
-
-
-class _PositionToken(Token):
-    def __init__( self ):
-        super(_PositionToken,self).__init__()
-        self.name=self.__class__.__name__
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-class GoToColumn(_PositionToken):
-    """Token to advance to a specific column of input text; useful for tabular report scraping."""
-    def __init__( self, colno ):
-        super(GoToColumn,self).__init__()
-        self.col = colno
-
-    def preParse( self, instring, loc ):
-        if col(loc,instring) != self.col:
-            instrlen = len(instring)
-            if self.ignoreExprs:
-                loc = self._skipIgnorables( instring, loc )
-            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
-                loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        thiscol = col( loc, instring )
-        if thiscol > self.col:
-            raise ParseException( instring, loc, "Text not in expected column", self )
-        newloc = loc + self.col - thiscol
-        ret = instring[ loc: newloc ]
-        return newloc, ret
-
-class LineStart(_PositionToken):
-    """Matches if current position is at the beginning of a line within the parse string"""
-    def __init__( self ):
-        super(LineStart,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected start of line"
-
-    def preParse( self, instring, loc ):
-        preloc = super(LineStart,self).preParse(instring,loc)
-        if instring[preloc] == "\n":
-            loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not( loc==0 or
-            (loc == self.preParse( instring, 0 )) or
-            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
-            #~ raise ParseException( instring, loc, "Expected start of line" )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        return loc, []
-
-class LineEnd(_PositionToken):
-    """Matches if current position is at the end of a line within the parse string"""
-    def __init__( self ):
-        super(LineEnd,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected end of line"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc<len(instring):
-            if instring[loc] == "\n":
-                return loc+1, "\n"
-            else:
-                #~ raise ParseException( instring, loc, "Expected end of line" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        elif loc == len(instring):
-            return loc+1, []
-        else:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-class StringStart(_PositionToken):
-    """Matches if current position is at the beginning of the parse string"""
-    def __init__( self ):
-        super(StringStart,self).__init__()
-        self.errmsg = "Expected start of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc != 0:
-            # see if entire string up to here is just whitespace and ignoreables
-            if loc != self.preParse( instring, 0 ):
-                #~ raise ParseException( instring, loc, "Expected start of text" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-class StringEnd(_PositionToken):
-    """Matches if current position is at the end of the parse string"""
-    def __init__( self ):
-        super(StringEnd,self).__init__()
-        self.errmsg = "Expected end of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc < len(instring):
-            #~ raise ParseException( instring, loc, "Expected end of text" )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        elif loc == len(instring):
-            return loc+1, []
-        elif loc > len(instring):
-            return loc, []
-        else:
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-
-class WordStart(_PositionToken):
-    """Matches if the current position is at the beginning of a Word, and
-       is not preceded by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of
-       the string being parsed, or at the beginning of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordStart,self).__init__()
-        self.wordChars = set(wordChars)
-        self.errmsg = "Not at the start of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        if loc != 0:
-            if (instring[loc-1] in self.wordChars or
-                instring[loc] not in self.wordChars):
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-class WordEnd(_PositionToken):
-    """Matches if the current position is at the end of a Word, and
-       is not followed by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of
-       the string being parsed, or at the end of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordEnd,self).__init__()
-        self.wordChars = set(wordChars)
-        self.skipWhitespace = False
-        self.errmsg = "Not at the end of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        instrlen = len(instring)
-        if instrlen>0 and loc<instrlen:
-            if (instring[loc] in self.wordChars or
-                instring[loc-1] not in self.wordChars):
-                #~ raise ParseException( instring, loc, "Expected end of word" )
-                exc = self.myException
-                exc.loc = loc
-                exc.pstr = instring
-                raise exc
-        return loc, []
-
-
-class ParseExpression(ParserElement):
-    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
-    def __init__( self, exprs, savelist = False ):
-        super(ParseExpression,self).__init__(savelist)
-        if isinstance( exprs, list ):
-            self.exprs = exprs
-        elif isinstance( exprs, basestring ):
-            self.exprs = [ Literal( exprs ) ]
-        else:
-            try:
-                self.exprs = list( exprs )
-            except TypeError:
-                self.exprs = [ exprs ]
-        self.callPreparse = False
-
-    def __getitem__( self, i ):
-        return self.exprs[i]
-
-    def append( self, other ):
-        self.exprs.append( other )
-        self.strRepr = None
-        return self
-
-    def leaveWhitespace( self ):
-        """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on
-           all contained expressions."""
-        self.skipWhitespace = False
-        self.exprs = [ e.copy() for e in self.exprs ]
-        for e in self.exprs:
-            e.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseExpression, self).ignore( other )
-                for e in self.exprs:
-                    e.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseExpression, self).ignore( other )
-            for e in self.exprs:
-                e.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def __str__( self ):
-        try:
-            return super(ParseExpression,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
-        return self.strRepr
-
-    def streamline( self ):
-        super(ParseExpression,self).streamline()
-
-        for e in self.exprs:
-            e.streamline()
-
-        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
-        # but only if there are no parse actions or resultsNames on the nested And's
-        # (likewise for Or's and MatchFirst's)
-        if ( len(self.exprs) == 2 ):
-            other = self.exprs[0]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = other.exprs[:] + [ self.exprs[1] ]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-            other = self.exprs[-1]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = self.exprs[:-1] + other.exprs[:]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
-        return ret
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        for e in self.exprs:
-            e.validate(tmp)
-        self.checkRecursion( [] )
-        
-    def copy(self):
-        ret = super(ParseExpression,self).copy()
-        ret.exprs = [e.copy() for e in self.exprs]
-        return ret
-
-class And(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found in the given order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'+'} operator.
-    """
-
-    class _ErrorStop(Empty):
-        def __init__(self, *args, **kwargs):
-            super(And._ErrorStop,self).__init__(*args, **kwargs)
-            self.leaveWhitespace()
-
-    def __init__( self, exprs, savelist = True ):
-        super(And,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.setWhitespaceChars( exprs[0].whiteChars )
-        self.skipWhitespace = exprs[0].skipWhitespace
-        self.callPreparse = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        # pass False as last arg to _parse for first element, since we already
-        # pre-parsed the string as part of our And pre-parsing
-        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
-        errorStop = False
-        for e in self.exprs[1:]:
-            if isinstance(e, And._ErrorStop):
-                errorStop = True
-                continue
-            if errorStop:
-                try:
-                    loc, exprtokens = e._parse( instring, loc, doActions )
-                except ParseSyntaxException:
-                    raise
-                except ParseBaseException:
-                    pe = sys.exc_info()[1]
-                    raise ParseSyntaxException(pe)
-                except IndexError:
-                    raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
-            else:
-                loc, exprtokens = e._parse( instring, loc, doActions )
-            if exprtokens or exprtokens.keys():
-                resultlist += exprtokens
-        return loc, resultlist
-
-    def __iadd__(self, other ):
-        if isinstance( other, basestring ):
-            other = Literal( other )
-        return self.append( other ) #And( [ self, other ] )
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-            if not e.mayReturnEmpty:
-                break
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-
-class Or(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the expression that matches the longest string will be used.
-       May be constructed using the C{'^'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(Or,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = False
-        for e in self.exprs:
-            if e.mayReturnEmpty:
-                self.mayReturnEmpty = True
-                break
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxMatchLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                loc2 = e.tryParse( instring, loc )
-            except ParseException:
-                err = sys.exc_info()[1]
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-            else:
-                if loc2 > maxMatchLoc:
-                    maxMatchLoc = loc2
-                    maxMatchExp = e
-
-        if maxMatchLoc < 0:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-        return maxMatchExp._parse( instring, loc, doActions )
-
-    def __ixor__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #Or( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class MatchFirst(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the first one listed is the one that will match.
-       May be constructed using the C{'|'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(MatchFirst,self).__init__(exprs, savelist)
-        if exprs:
-            self.mayReturnEmpty = False
-            for e in self.exprs:
-                if e.mayReturnEmpty:
-                    self.mayReturnEmpty = True
-                    break
-        else:
-            self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                ret = e._parse( instring, loc, doActions )
-                return ret
-            except ParseException, err:
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-
-        # only got here if no expression matched, raise exception for match that made it the furthest
-        else:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-    def __ior__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #MatchFirst( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class Each(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found, but in any order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'&'} operator.
-    """
-    def __init__( self, exprs, savelist = True ):
-        super(Each,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.skipWhitespace = True
-        self.initExprGroups = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.initExprGroups:
-            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
-            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ]
-            self.optionals = opt1 + opt2
-            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
-            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
-            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
-            self.required += self.multirequired
-            self.initExprGroups = False
-        tmpLoc = loc
-        tmpReqd = self.required[:]
-        tmpOpt  = self.optionals[:]
-        matchOrder = []
-
-        keepMatching = True
-        while keepMatching:
-            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
-            failed = []
-            for e in tmpExprs:
-                try:
-                    tmpLoc = e.tryParse( instring, tmpLoc )
-                except ParseException:
-                    failed.append(e)
-                else:
-                    matchOrder.append(e)
-                    if e in tmpReqd:
-                        tmpReqd.remove(e)
-                    elif e in tmpOpt:
-                        tmpOpt.remove(e)
-            if len(failed) == len(tmpExprs):
-                keepMatching = False
-
-        if tmpReqd:
-            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
-            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
-
-        # add any unmatched Optionals, in case they have default values defined
-        matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]
-
-        resultlist = []
-        for e in matchOrder:
-            loc,results = e._parse(instring,loc,doActions)
-            resultlist.append(results)
-
-        finalResults = ParseResults([])
-        for r in resultlist:
-            dups = {}
-            for k in r.keys():
-                if k in finalResults.keys():
-                    tmp = ParseResults(finalResults[k])
-                    tmp += ParseResults(r[k])
-                    dups[k] = tmp
-            finalResults += ParseResults(r)
-            for k,v in dups.items():
-                finalResults[k] = v
-        return loc, finalResults
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class ParseElementEnhance(ParserElement):
-    """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens."""
-    def __init__( self, expr, savelist=False ):
-        super(ParseElementEnhance,self).__init__(savelist)
-        if isinstance( expr, basestring ):
-            expr = Literal(expr)
-        self.expr = expr
-        self.strRepr = None
-        if expr is not None:
-            self.mayIndexError = expr.mayIndexError
-            self.mayReturnEmpty = expr.mayReturnEmpty
-            self.setWhitespaceChars( expr.whiteChars )
-            self.skipWhitespace = expr.skipWhitespace
-            self.saveAsList = expr.saveAsList
-            self.callPreparse = expr.callPreparse
-            self.ignoreExprs.extend(expr.ignoreExprs)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.expr is not None:
-            return self.expr._parse( instring, loc, doActions, callPreParse=False )
-        else:
-            raise ParseException("",loc,self.errmsg,self)
-
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        self.expr = self.expr.copy()
-        if self.expr is not None:
-            self.expr.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseElementEnhance, self).ignore( other )
-                if self.expr is not None:
-                    self.expr.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseElementEnhance, self).ignore( other )
-            if self.expr is not None:
-                self.expr.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def streamline( self ):
-        super(ParseElementEnhance,self).streamline()
-        if self.expr is not None:
-            self.expr.streamline()
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        if self in parseElementList:
-            raise RecursiveGrammarException( parseElementList+[self] )
-        subRecCheckList = parseElementList[:] + [ self ]
-        if self.expr is not None:
-            self.expr.checkRecursion( subRecCheckList )
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        if self.expr is not None:
-            self.expr.validate(tmp)
-        self.checkRecursion( [] )
-
-    def __str__( self ):
-        try:
-            return super(ParseElementEnhance,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None and self.expr is not None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
-        return self.strRepr
-
-
-class FollowedBy(ParseElementEnhance):
-    """Lookahead matching of the given parse expression.  C{FollowedBy}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression matches at the current
-    position.  C{FollowedBy} always returns a null token list."""
-    def __init__( self, expr ):
-        super(FollowedBy,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        self.expr.tryParse( instring, loc )
-        return loc, []
-
-
-class NotAny(ParseElementEnhance):
-    """Lookahead to disallow matching with the given parse expression.  C{NotAny}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression does *not* match at the current
-    position.  Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny}
-    always returns a null token list.  May be constructed using the '~' operator."""
-    def __init__( self, expr ):
-        super(NotAny,self).__init__(expr)
-        #~ self.leaveWhitespace()
-        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
-        self.mayReturnEmpty = True
-        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            self.expr.tryParse( instring, loc )
-        except (ParseException,IndexError):
-            pass
-        else:
-            #~ raise ParseException(instring, loc, self.errmsg )
-            exc = self.myException
-            exc.loc = loc
-            exc.pstr = instring
-            raise exc
-        return loc, []
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "~{" + _ustr(self.expr) + "}"
-
-        return self.strRepr
-
-
-class ZeroOrMore(ParseElementEnhance):
-    """Optional repetition of zero or more of the given expression."""
-    def __init__( self, expr ):
-        super(ZeroOrMore,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        tokens = []
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-
-class OneOrMore(ParseElementEnhance):
-    """Repetition of one or more of the given expression."""
-    def parseImpl( self, instring, loc, doActions=True ):
-        # must be at least one
-        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        try:
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + _ustr(self.expr) + "}..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-class _NullToken(object):
-    def __bool__(self):
-        return False
-    __nonzero__ = __bool__
-    def __str__(self):
-        return ""
-
-_optionalNotMatched = _NullToken()
-class Optional(ParseElementEnhance):
-    """Optional matching of the given expression.
-       A default return string can also be specified, if the optional expression
-       is not found.
-    """
-    def __init__( self, exprs, default=_optionalNotMatched ):
-        super(Optional,self).__init__( exprs, savelist=False )
-        self.defaultValue = default
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        except (ParseException,IndexError):
-            if self.defaultValue is not _optionalNotMatched:
-                if self.expr.resultsName:
-                    tokens = ParseResults([ self.defaultValue ])
-                    tokens[self.expr.resultsName] = self.defaultValue
-                else:
-                    tokens = [ self.defaultValue ]
-            else:
-                tokens = []
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]"
-
-        return self.strRepr
-
-
-class SkipTo(ParseElementEnhance):
-    """Token for skipping over all undefined text until the matched expression is found.
-       If C{include} is set to true, the matched expression is also parsed (the skipped text
-       and matched expression are returned as a 2-element list).  The C{ignore}
-       argument is used to define grammars (typically quoted strings and comments) that
-       might contain false matches.
-    """
-    def __init__( self, other, include=False, ignore=None, failOn=None ):
-        super( SkipTo, self ).__init__( other )
-        self.ignoreExpr = ignore
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.includeMatch = include
-        self.asList = False
-        if failOn is not None and isinstance(failOn, basestring):
-            self.failOn = Literal(failOn)
-        else:
-            self.failOn = failOn
-        self.errmsg = "No match found for "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        startLoc = loc
-        instrlen = len(instring)
-        expr = self.expr
-        failParse = False
-        while loc <= instrlen:
-            try:
-                if self.failOn:
-                    try:
-                        self.failOn.tryParse(instring, loc)
-                    except ParseBaseException:
-                        pass
-                    else:
-                        failParse = True
-                        raise ParseException(instring, loc, "Found expression " + str(self.failOn))
-                    failParse = False
-                if self.ignoreExpr is not None:
-                    while 1:
-                        try:
-                            loc = self.ignoreExpr.tryParse(instring,loc)
-                            # print "found ignoreExpr, advance to", loc
-                        except ParseBaseException:
-                            break
-                expr._parse( instring, loc, doActions=False, callPreParse=False )
-                skipText = instring[startLoc:loc]
-                if self.includeMatch:
-                    loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
-                    if mat:
-                        skipRes = ParseResults( skipText )
-                        skipRes += mat
-                        return loc, [ skipRes ]
-                    else:
-                        return loc, [ skipText ]
-                else:
-                    return loc, [ skipText ]
-            except (ParseException,IndexError):
-                if failParse:
-                    raise
-                else:
-                    loc += 1
-        exc = self.myException
-        exc.loc = loc
-        exc.pstr = instring
-        raise exc
-
-class Forward(ParseElementEnhance):
-    """Forward declaration of an expression to be defined later -
-       used for recursive grammars, such as algebraic infix notation.
-       When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.
-
-       Note: take care when assigning to C{Forward} not to overlook precedence of operators.
-       Specifically, '|' has a lower precedence than '<<', so that::
-          fwdExpr << a | b | c
-       will actually be evaluated as::
-          (fwdExpr << a) | b | c
-       thereby leaving b and c out as parseable alternatives.  It is recommended that you
-       explicitly group the values inserted into the C{Forward}::
-          fwdExpr << (a | b | c)
-       Converting to use the '<<=' operator instead will avoid this problem.
-    """
-    def __init__( self, other=None ):
-        super(Forward,self).__init__( other, savelist=False )
-
-    def __lshift__( self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass(other)
-        self.expr = other
-        self.mayReturnEmpty = other.mayReturnEmpty
-        self.strRepr = None
-        self.mayIndexError = self.expr.mayIndexError
-        self.mayReturnEmpty = self.expr.mayReturnEmpty
-        self.setWhitespaceChars( self.expr.whiteChars )
-        self.skipWhitespace = self.expr.skipWhitespace
-        self.saveAsList = self.expr.saveAsList
-        self.ignoreExprs.extend(self.expr.ignoreExprs)
-        return None
-    __ilshift__ = __lshift__
-    
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        return self
-
-    def streamline( self ):
-        if not self.streamlined:
-            self.streamlined = True
-            if self.expr is not None:
-                self.expr.streamline()
-        return self
-
-    def validate( self, validateTrace=[] ):
-        if self not in validateTrace:
-            tmp = validateTrace[:]+[self]
-            if self.expr is not None:
-                self.expr.validate(tmp)
-        self.checkRecursion([])
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        self._revertClass = self.__class__
-        self.__class__ = _ForwardNoRecurse
-        try:
-            if self.expr is not None:
-                retString = _ustr(self.expr)
-            else:
-                retString = "None"
-        finally:
-            self.__class__ = self._revertClass
-        return self.__class__.__name__ + ": " + retString
-
-    def copy(self):
-        if self.expr is not None:
-            return super(Forward,self).copy()
-        else:
-            ret = Forward()
-            ret << self
-            return ret
-
-class _ForwardNoRecurse(Forward):
-    def __str__( self ):
-        return "..."
-
-class TokenConverter(ParseElementEnhance):
-    """Abstract subclass of C{ParseExpression}, for converting parsed results."""
-    def __init__( self, expr, savelist=False ):
-        super(TokenConverter,self).__init__( expr )#, savelist )
-        self.saveAsList = False
-
-class Upcase(TokenConverter):
-    """Converter to upper case all matching tokens."""
-    def __init__(self, *args):
-        super(Upcase,self).__init__(*args)
-        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
-                       DeprecationWarning,stacklevel=2)
-
-    def postParse( self, instring, loc, tokenlist ):
-        return list(map( string.upper, tokenlist ))
-
-
-class Combine(TokenConverter):
-    """Converter to concatenate all matching tokens to a single string.
-       By default, the matching patterns must also be contiguous in the input string;
-       this can be disabled by specifying C{'adjacent=False'} in the constructor.
-    """
-    def __init__( self, expr, joinString="", adjacent=True ):
-        super(Combine,self).__init__( expr )
-        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
-        if adjacent:
-            self.leaveWhitespace()
-        self.adjacent = adjacent
-        self.skipWhitespace = True
-        self.joinString = joinString
-        self.callPreparse = True
-
-    def ignore( self, other ):
-        if self.adjacent:
-            ParserElement.ignore(self, other)
-        else:
-            super( Combine, self).ignore( other )
-        return self
-
-    def postParse( self, instring, loc, tokenlist ):
-        retToks = tokenlist.copy()
-        del retToks[:]
-        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
-
-        if self.resultsName and len(retToks.keys())>0:
-            return [ retToks ]
-        else:
-            return retToks
-
-class Group(TokenConverter):
-    """Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions."""
-    def __init__( self, expr ):
-        super(Group,self).__init__( expr )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        return [ tokenlist ]
-
-class Dict(TokenConverter):
-    """Converter to return a repetitive expression as a list, but also as a dictionary.
-       Each element can also be referenced using the first token in the expression as its key.
-       Useful for tabular report scraping when the first column can be used as a item key.
-    """
-    def __init__( self, exprs ):
-        super(Dict,self).__init__( exprs )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        for i,tok in enumerate(tokenlist):
-            if len(tok) == 0:
-                continue
-            ikey = tok[0]
-            if isinstance(ikey,int):
-                ikey = _ustr(tok[0]).strip()
-            if len(tok)==1:
-                tokenlist[ikey] = _ParseResultsWithOffset("",i)
-            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
-                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
-            else:
-                dictvalue = tok.copy() #ParseResults(i)
-                del dictvalue[0]
-                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
-                else:
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
-
-        if self.resultsName:
-            return [ tokenlist ]
-        else:
-            return tokenlist
-
-
-class Suppress(TokenConverter):
-    """Converter for ignoring the results of a parsed expression."""
-    def postParse( self, instring, loc, tokenlist ):
-        return []
-
-    def suppress( self ):
-        return self
-
-
-class OnlyOnce(object):
-    """Wrapper for parse actions, to ensure they are only called once."""
-    def __init__(self, methodCall):
-        self.callable = _trim_arity(methodCall)
-        self.called = False
-    def __call__(self,s,l,t):
-        if not self.called:
-            results = self.callable(s,l,t)
-            self.called = True
-            return results
-        raise ParseException(s,l,"")
-    def reset(self):
-        self.called = False
-
-def traceParseAction(f):
-    """Decorator for debugging parse actions."""
-    f = _trim_arity(f)
-    def z(*paArgs):
-        thisFunc = f.func_name
-        s,l,t = paArgs[-3:]
-        if len(paArgs)>3:
-            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
-        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
-        try:
-            ret = f(*paArgs)
-        except Exception:
-            exc = sys.exc_info()[1]
-            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
-            raise
-        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
-        return ret
-    try:
-        z.__name__ = f.__name__
-    except AttributeError:
-        pass
-    return z
-
-#
-# global helpers
-#
-def delimitedList( expr, delim=",", combine=False ):
-    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
-       By default, the list elements and delimiters can have intervening whitespace, and
-       comments, but this can be overridden by passing C{combine=True} in the constructor.
-       If C{combine} is set to C{True}, the matching tokens are returned as a single token
-       string, with the delimiters included; otherwise, the matching tokens are returned
-       as a list of tokens, with the delimiters suppressed.
-    """
-    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
-    if combine:
-        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
-    else:
-        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
-
-def countedArray( expr, intExpr=None ):
-    """Helper to define a counted list of expressions.
-       This helper defines a pattern of the form::
-           integer expr expr expr...
-       where the leading integer tells how many expr expressions follow.
-       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
-    """
-    arrayExpr = Forward()
-    def countFieldParseAction(s,l,t):
-        n = t[0]
-        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
-        return []
-    if intExpr is None:
-        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
-    else:
-        intExpr = intExpr.copy()
-    intExpr.setName("arrayLen")
-    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
-    return ( intExpr + arrayExpr )
-
-def _flatten(L):
-    ret = []
-    for i in L:
-        if isinstance(i,list):
-            ret.extend(_flatten(i))
-        else:
-            ret.append(i)
-    return ret
-
-def matchPreviousLiteral(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousLiteral(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches a
-       previous literal, will also match the leading C{"1:1"} in C{"1:10"}.
-       If this is not desired, use C{matchPreviousExpr}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    def copyTokenToRepeater(s,l,t):
-        if t:
-            if len(t) == 1:
-                rep << t[0]
-            else:
-                # flatten t tokens
-                tflat = _flatten(t.asList())
-                rep << And( [ Literal(tt) for tt in tflat ] )
-        else:
-            rep << Empty()
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def matchPreviousExpr(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousExpr(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches by
-       expressions, will *not* match the leading C{"1:1"} in C{"1:10"};
-       the expressions are evaluated first, and then compared, so
-       C{"1"} is compared with C{"10"}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    e2 = expr.copy()
-    rep << e2
-    def copyTokenToRepeater(s,l,t):
-        matchTokens = _flatten(t.asList())
-        def mustMatchTheseTokens(s,l,t):
-            theseTokens = _flatten(t.asList())
-            if  theseTokens != matchTokens:
-                raise ParseException("",0,"")
-        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def _escapeRegexRangeChars(s):
-    #~  escape these chars: ^-]
-    for c in r"\^-]":
-        s = s.replace(c,_bslash+c)
-    s = s.replace("\n",r"\n")
-    s = s.replace("\t",r"\t")
-    return _ustr(s)
-
-def oneOf( strs, caseless=False, useRegex=True ):
-    """Helper to quickly define a set of alternative Literals, and makes sure to do
-       longest-first testing when there is a conflict, regardless of the input order,
-       but returns a C{L{MatchFirst}} for best performance.
-
-       Parameters:
-        - strs - a string of space-delimited literals, or a list of string literals
-        - caseless - (default=False) - treat all literals as caseless
-        - useRegex - (default=True) - as an optimization, will generate a Regex
-          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or
-          if creating a C{Regex} raises an exception)
-    """
-    if caseless:
-        isequal = ( lambda a,b: a.upper() == b.upper() )
-        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
-        parseElementClass = CaselessLiteral
-    else:
-        isequal = ( lambda a,b: a == b )
-        masks = ( lambda a,b: b.startswith(a) )
-        parseElementClass = Literal
-
-    if isinstance(strs,(list,tuple)):
-        symbols = list(strs[:])
-    elif isinstance(strs,basestring):
-        symbols = strs.split()
-    else:
-        warnings.warn("Invalid argument to oneOf, expected string or list",
-                SyntaxWarning, stacklevel=2)
-
-    i = 0
-    while i < len(symbols)-1:
-        cur = symbols[i]
-        for j,other in enumerate(symbols[i+1:]):
-            if ( isequal(other, cur) ):
-                del symbols[i+j+1]
-                break
-            elif ( masks(cur, other) ):
-                del symbols[i+j+1]
-                symbols.insert(i,other)
-                cur = other
-                break
-        else:
-            i += 1
-
-    if not caseless and useRegex:
-        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
-        try:
-            if len(symbols)==len("".join(symbols)):
-                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
-            else:
-                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
-        except:
-            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
-                    SyntaxWarning, stacklevel=2)
-
-
-    # last resort, just use MatchFirst
-    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
-
-def dictOf( key, value ):
-    """Helper to easily and clearly define a dictionary by specifying the respective patterns
-       for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens
-       in the proper order.  The key pattern can include delimiting markers or punctuation,
-       as long as they are suppressed, thereby leaving the significant key text.  The value
-       pattern can include named results, so that the C{Dict} results can include named token
-       fields.
-    """
-    return Dict( ZeroOrMore( Group ( key + value ) ) )
-
-def originalTextFor(expr, asString=True):
-    """Helper to return the original, untokenized text for a given expression.  Useful to
-       restore the parsed fields of an HTML start tag into the raw tag text itself, or to
-       revert separate tokens with intervening whitespace back to the original matching
-       input text. Simpler to use than the parse action C{L{keepOriginalText}}, and does not
-       require the inspect module to chase up the call stack.  By default, returns a 
-       string containing the original parsed text.  
-       
-       If the optional C{asString} argument is passed as C{False}, then the return value is a 
-       C{L{ParseResults}} containing any results names that were originally matched, and a 
-       single token containing the original matched text from the input string.  So if 
-       the expression passed to C{L{originalTextFor}} contains expressions with defined
-       results names, you must set C{asString} to C{False} if you want to preserve those
-       results name values."""
-    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
-    endlocMarker = locMarker.copy()
-    endlocMarker.callPreparse = False
-    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
-    if asString:
-        extractText = lambda s,l,t: s[t._original_start:t._original_end]
-    else:
-        def extractText(s,l,t):
-            del t[:]
-            t.insert(0, s[t._original_start:t._original_end])
-            del t["_original_start"]
-            del t["_original_end"]
-    matchExpr.setParseAction(extractText)
-    return matchExpr
-
-def ungroup(expr): 
-    """Helper to undo pyparsing's default grouping of And expressions, even
-       if all but one are non-empty."""
-    return TokenConverter(expr).setParseAction(lambda t:t[0])
-
-# convenience constants for positional expressions
-empty       = Empty().setName("empty")
-lineStart   = LineStart().setName("lineStart")
-lineEnd     = LineEnd().setName("lineEnd")
-stringStart = StringStart().setName("stringStart")
-stringEnd   = StringEnd().setName("stringEnd")
-
-_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
-_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
-_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
-_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
-_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
-_charRange = Group(_singleChar + Suppress("-") + _singleChar)
-_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
-
-_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
-
-def srange(s):
-    r"""Helper to easily define string ranges for use in Word construction.  Borrows
-       syntax from regexp '[]' string range definitions::
-          srange("[0-9]")   -> "0123456789"
-          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
-          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
-       The input string must be enclosed in []'s, and the returned string is the expanded
-       character set joined into a single string.
-       The values enclosed in the []'s may be::
-          a single character
-          an escaped character with a leading backslash (such as \- or \])
-          an escaped hex character with a leading '\x' (\x21, which is a '!' character) 
-            (\0x## is also supported for backwards compatibility) 
-          an escaped octal character with a leading '\0' (\041, which is a '!' character)
-          a range of any of the above, separated by a dash ('a-z', etc.)
-          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
-    """
-    try:
-        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
-    except:
-        return ""
-
-def matchOnlyAtCol(n):
-    """Helper method for defining parse actions that require matching at a specific
-       column in the input text.
-    """
-    def verifyCol(strg,locn,toks):
-        if col(locn,strg) != n:
-            raise ParseException(strg,locn,"matched token not at column %d" % n)
-    return verifyCol
-
-def replaceWith(replStr):
-    """Helper method for common parse actions that simply return a literal value.  Especially
-       useful when used with C{L{transformString<ParserElement.transformString>}()}.
-    """
-    def _replFunc(*args):
-        return [replStr]
-    return _replFunc
-
-def removeQuotes(s,l,t):
-    """Helper parse action for removing quotation marks from parsed quoted strings.
-       To use, add this parse action to quoted string using::
-         quotedString.setParseAction( removeQuotes )
-    """
-    return t[0][1:-1]
-
-def upcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to upper case."""
-    return [ tt.upper() for tt in map(_ustr,t) ]
-
-def downcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to lower case."""
-    return [ tt.lower() for tt in map(_ustr,t) ]
-
-def keepOriginalText(s,startLoc,t):
-    """DEPRECATED - use new helper method C{L{originalTextFor}}.
-       Helper parse action to preserve original parsed text,
-       overriding any nested parse actions."""
-    try:
-        endloc = getTokensEndLoc()
-    except ParseException:
-        raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
-    del t[:]
-    t += ParseResults(s[startLoc:endloc])
-    return t
-
-def getTokensEndLoc():
-    """Method to be called from within a parse action to determine the end
-       location of the parsed tokens."""
-    import inspect
-    fstack = inspect.stack()
-    try:
-        # search up the stack (through intervening argument normalizers) for correct calling routine
-        for f in fstack[2:]:
-            if f[3] == "_parseNoCache":
-                endloc = f[0].f_locals["loc"]
-                return endloc
-        else:
-            raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
-    finally:
-        del fstack
-
-def _makeTags(tagStr, xml):
-    """Internal helper to construct opening and closing tag expressions, given a tag name"""
-    if isinstance(tagStr,basestring):
-        resname = tagStr
-        tagStr = Keyword(tagStr, caseless=not xml)
-    else:
-        resname = tagStr.name
-
-    tagAttrName = Word(alphas,alphanums+"_-:")
-    if (xml):
-        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    else:
-        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
-        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
-                Optional( Suppress("=") + tagAttrValue ) ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    closeTag = Combine(_L("</") + tagStr + ">")
-
-    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
-    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
-    openTag.tag = resname
-    closeTag.tag = resname
-    return openTag, closeTag
-
-def makeHTMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
-    return _makeTags( tagStr, False )
-
-def makeXMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
-    return _makeTags( tagStr, True )
-
-def withAttribute(*args,**attrDict):
-    """Helper to create a validating parse action to be used with start tags created
-       with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag
-       with a required attribute value, to avoid false matches on common tags such as
-       C{<TD>} or C{<DIV>}.
-
-       Call C{withAttribute} with a series of attribute names and values. Specify the list
-       of filter attributes names and values as:
-        - keyword arguments, as in C{(align="right")}, or
-        - as an explicit dict with C{**} operator, when an attribute name is also a Python
-          reserved word, as in C{**{"class":"Customer", "align":"right"}}
-        - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
-       For attribute names with a namespace prefix, you must use the second form.  Attribute
-       names are matched insensitive to upper/lower case.
-
-       To verify that the attribute exists, but without specifying a value, pass
-       C{withAttribute.ANY_VALUE} as the value.
-       """
-    if args:
-        attrs = args[:]
-    else:
-        attrs = attrDict.items()
-    attrs = [(k,v) for k,v in attrs]
-    def pa(s,l,tokens):
-        for attrName,attrValue in attrs:
-            if attrName not in tokens:
-                raise ParseException(s,l,"no matching attribute " + attrName)
-            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
-                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
-                                            (attrName, tokens[attrName], attrValue))
-    return pa
-withAttribute.ANY_VALUE = object()
-
-opAssoc = _Constants()
-opAssoc.LEFT = object()
-opAssoc.RIGHT = object()
-
-def operatorPrecedence( baseExpr, opList ):
-    """Helper method for constructing grammars of expressions made up of
-       operators working in a precedence hierarchy.  Operators may be unary or
-       binary, left- or right-associative.  Parse actions can also be attached
-       to operator expressions.
-
-       Parameters:
-        - baseExpr - expression representing the most basic element for the nested
-        - opList - list of tuples, one for each operator precedence level in the
-          expression grammar; each tuple is of the form
-          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
-           - opExpr is the pyparsing expression for the operator;
-              may also be a string, which will be converted to a Literal;
-              if numTerms is 3, opExpr is a tuple of two expressions, for the
-              two operators separating the 3 terms
-           - numTerms is the number of terms for this operator (must
-              be 1, 2, or 3)
-           - rightLeftAssoc is the indicator whether the operator is
-              right or left associative, using the pyparsing-defined
-              constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.
-           - parseAction is the parse action to be associated with
-              expressions matching this operator expression (the
-              parse action tuple member may be omitted)
-    """
-    ret = Forward()
-    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
-    for i,operDef in enumerate(opList):
-        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
-        if arity == 3:
-            if opExpr is None or len(opExpr) != 2:
-                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
-            opExpr1, opExpr2 = opExpr
-        thisExpr = Forward()#.setName("expr%d" % i)
-        if rightLeftAssoc == opAssoc.LEFT:
-            if arity == 1:
-                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
-                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        elif rightLeftAssoc == opAssoc.RIGHT:
-            if arity == 1:
-                # try to avoid LR with this extra test
-                if not isinstance(opExpr, Optional):
-                    opExpr = Optional(opExpr)
-                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
-                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        else:
-            raise ValueError("operator must indicate right or left associativity")
-        if pa:
-            matchExpr.setParseAction( pa )
-        thisExpr << ( matchExpr | lastExpr )
-        lastExpr = thisExpr
-    ret << lastExpr
-    return ret
-
-dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
-sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
-quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
-unicodeString = Combine(_L('u') + quotedString.copy())
-
-def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()):
-    """Helper method for defining nested lists enclosed in opening and closing
-       delimiters ("(" and ")" are the default).
-
-       Parameters:
-        - opener - opening character for a nested list (default="("); can also be a pyparsing expression
-        - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
-        - content - expression for items within the nested lists (default=None)
-        - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
-
-       If an expression is not provided for the content argument, the nested
-       expression will capture all whitespace-delimited content between delimiters
-       as a list of separate values.
-
-       Use the C{ignoreExpr} argument to define expressions that may contain
-       opening or closing characters that should not be treated as opening
-       or closing characters for nesting, such as quotedString or a comment
-       expression.  Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}.
-       The default is L{quotedString}, but if no expressions are to be ignored,
-       then pass C{None} for this argument.
-    """
-    if opener == closer:
-        raise ValueError("opening and closing strings cannot be the same")
-    if content is None:
-        if isinstance(opener,basestring) and isinstance(closer,basestring):
-            if len(opener) == 1 and len(closer)==1:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr +
-                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
-                                ).setParseAction(lambda t:t[0].strip()))
-            else:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr + 
-                                    ~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-        else:
-            raise ValueError("opening and closing arguments must be strings if no content expression is given")
-    ret = Forward()
-    if ignoreExpr is not None:
-        ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
-    else:
-        ret << Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )
-    return ret
-
-def indentedBlock(blockStatementExpr, indentStack, indent=True):
-    """Helper method for defining space-delimited indentation blocks, such as
-       those used to define block statements in Python source code.
-
-       Parameters:
-        - blockStatementExpr - expression defining syntax of statement that
-            is repeated within the indented block
-        - indentStack - list created by caller to manage indentation stack
-            (multiple statementWithIndentedBlock expressions within a single grammar
-            should share a common indentStack)
-        - indent - boolean indicating whether block must be indented beyond the
-            the current level; set to False for block of left-most statements
-            (default=True)
-
-       A valid block must contain at least one C{blockStatement}.
-    """
-    def checkPeerIndent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if curCol != indentStack[-1]:
-            if curCol > indentStack[-1]:
-                raise ParseFatalException(s,l,"illegal nesting")
-            raise ParseException(s,l,"not a peer entry")
-
-    def checkSubIndent(s,l,t):
-        curCol = col(l,s)
-        if curCol > indentStack[-1]:
-            indentStack.append( curCol )
-        else:
-            raise ParseException(s,l,"not a subentry")
-
-    def checkUnindent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
-            raise ParseException(s,l,"not an unindent")
-        indentStack.pop()
-
-    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
-    INDENT = Empty() + Empty().setParseAction(checkSubIndent)
-    PEER   = Empty().setParseAction(checkPeerIndent)
-    UNDENT = Empty().setParseAction(checkUnindent)
-    if indent:
-        smExpr = Group( Optional(NL) +
-            #~ FollowedBy(blockStatementExpr) +
-            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
-    else:
-        smExpr = Group( Optional(NL) +
-            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
-    blockStatementExpr.ignore(_bslash + LineEnd())
-    return smExpr
-
-alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
-punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
-
-anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
-commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
-_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
-replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
-
-# it's easy to get these comment structures wrong - they're very common, so may as well make them available
-cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
-
-htmlComment = Regex(r"<!--[\s\S]*?-->")
-restOfLine = Regex(r".*").leaveWhitespace()
-dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
-cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
-
-javaStyleComment = cppStyleComment
-pythonStyleComment = Regex(r"#.*").setName("Python style comment")
-_noncomma = "".join( [ c for c in printables if c != "," ] )
-_commasepitem = Combine(OneOrMore(Word(_noncomma) +
-                                  Optional( Word(" \t") +
-                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
-commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList")
-
-
-if __name__ == "__main__":
-
-    def test( teststring ):
-        try:
-            tokens = simpleSQL.parseString( teststring )
-            tokenlist = tokens.asList()
-            print (teststring + "->"   + str(tokenlist))
-            print ("tokens = "         + str(tokens))
-            print ("tokens.columns = " + str(tokens.columns))
-            print ("tokens.tables = "  + str(tokens.tables))
-            print (tokens.asXML("SQL",True))
-        except ParseBaseException:
-            err = sys.exc_info()[1]
-            print (teststring + "->")
-            print (err.line)
-            print (" "*(err.column-1) + "^")
-            print (err)
-        print()
-
-    selectToken    = CaselessLiteral( "select" )
-    fromToken      = CaselessLiteral( "from" )
-
-    ident          = Word( alphas, alphanums + "_$" )
-    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
-    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
-    simpleSQL      = ( selectToken + \
-                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
-                     fromToken + \
-                     tableNameList.setResultsName( "tables" ) )
-
-    test( "SELECT * from XYZZY, ABC" )
-    test( "select * from SYS.XYZZY" )
-    test( "Select A from Sys.dual" )
-    test( "Select AA,BB,CC from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Xelect A, B, C from Sys.dual" )
-    test( "Select A, B, C frox Sys.dual" )
-    test( "Select" )
-    test( "Select ^^^ frox Sys.dual" )
-    test( "Select A, B, C from Sys.dual, Table2   " )
diff --git a/src/pyparsing_py3.py b/src/pyparsing_py3.py
deleted file mode 100644
--- a/src/pyparsing_py3.py
+++ /dev/null
@@ -1,3595 +0,0 @@
-# module pyparsing.py
-#
-# Copyright (c) 2003-2011  Paul T. McGuire
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-#from __future__ import generators
-
-__doc__ = \
-"""
-pyparsing module - Classes and methods to define and execute parsing grammars
-
-The pyparsing module is an alternative approach to creating and executing simple grammars,
-vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
-don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
-provides a library of classes that you use to construct the grammar directly in Python.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form C{"<salutation>, <addressee>!"})::
-
-    from pyparsing import Word, alphas
-
-    # define grammar of a greeting
-    greet = Word( alphas ) + "," + Word( alphas ) + "!"
-
-    hello = "Hello, World!"
-    print hello, "->", greet.parseString( hello )
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the self-explanatory
-class names, and the use of '+', '|' and '^' operators.
-
-The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an
-object with named attributes.
-
-The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
- - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
- - quoted strings
- - embedded comments
-"""
-
-__version__ = "1.5.7"
-__versionTime__ = "3 August 2012 05:00"
-__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
-
-import string
-from weakref import ref as wkref
-import copy
-import sys
-import warnings
-import re
-import sre_constants
-import collections
-#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
-
-__all__ = [
-'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
-'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
-'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
-'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
-'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
-'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase',
-'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
-'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
-'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
-'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums',
-'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
-'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
-'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
-'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
-'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
-'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
-'indentedBlock', 'originalTextFor', 'ungroup',
-]
-
-_MAX_INT = sys.maxsize
-basestring = str
-unichr = chr
-_ustr = str
-
-# build list of single arg builtins, that can be used as parse actions
-singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max]
-
-def _xml_escape(data):
-    """Escape &, <, >, ", ', etc. in a string of data."""
-
-    # ampersand must be replaced first
-    from_symbols = '&><"\''
-    to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()]
-    for from_,to_ in zip(from_symbols, to_symbols):
-        data = data.replace(from_, to_)
-    return data
-
-class _Constants(object):
-    pass
-
-alphas = string.ascii_lowercase + string.ascii_uppercase
-nums       = "0123456789"
-hexnums    = nums + "ABCDEFabcdef"
-alphanums  = alphas + nums
-_bslash    = chr(92)
-printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
-
-class ParseBaseException(Exception):
-    """base exception class for all parsing runtime exceptions"""
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, pstr, loc=0, msg=None, elem=None ):
-        self.loc = loc
-        if msg is None:
-            self.msg = pstr
-            self.pstr = ""
-        else:
-            self.msg = msg
-            self.pstr = pstr
-        self.parserElement = elem
-
-    def __getattr__( self, aname ):
-        """supported attributes by name are:
-            - lineno - returns the line number of the exception text
-            - col - returns the column number of the exception text
-            - line - returns the line containing the exception text
-        """
-        if( aname == "lineno" ):
-            return lineno( self.loc, self.pstr )
-        elif( aname in ("col", "column") ):
-            return col( self.loc, self.pstr )
-        elif( aname == "line" ):
-            return line( self.loc, self.pstr )
-        else:
-            raise AttributeError(aname)
-
-    def __str__( self ):
-        return "%s (at char %d), (line:%d, col:%d)" % \
-                ( self.msg, self.loc, self.lineno, self.column )
-    def __repr__( self ):
-        return _ustr(self)
-    def markInputline( self, markerString = ">!<" ):
-        """Extracts the exception line from the input string, and marks
-           the location of the exception with a special symbol.
-        """
-        line_str = self.line
-        line_column = self.column - 1
-        if markerString:
-            line_str = "".join( [line_str[:line_column],
-                                markerString, line_str[line_column:]])
-        return line_str.strip()
-    def __dir__(self):
-        return "loc msg pstr parserElement lineno col line " \
-               "markInputline __str__ __repr__".split()
-
-class ParseException(ParseBaseException):
-    """exception thrown when parse expressions don't match class;
-       supported attributes by name are:
-        - lineno - returns the line number of the exception text
-        - col - returns the column number of the exception text
-        - line - returns the line containing the exception text
-    """
-    pass
-
-class ParseFatalException(ParseBaseException):
-    """user-throwable exception thrown when inconsistent parse content
-       is found; stops all parsing immediately"""
-    pass
-
-class ParseSyntaxException(ParseFatalException):
-    """just like C{L{ParseFatalException}}, but thrown internally when an
-       C{L{ErrorStop<And._ErrorStop>}} ('-' operator) indicates that parsing is to stop immediately because
-       an unbacktrackable syntax error has been found"""
-    def __init__(self, pe):
-        super(ParseSyntaxException, self).__init__(
-                                    pe.pstr, pe.loc, pe.msg, pe.parserElement)
-
-#~ class ReparseException(ParseBaseException):
-    #~ """Experimental class - parse actions can raise this exception to cause
-       #~ pyparsing to reparse the input string:
-        #~ - with a modified input string, and/or
-        #~ - with a modified start location
-       #~ Set the values of the ReparseException in the constructor, and raise the
-       #~ exception in a parse action to cause pyparsing to use the new string/location.
-       #~ Setting the values as None causes no change to be made.
-       #~ """
-    #~ def __init_( self, newstring, restartLoc ):
-        #~ self.newParseText = newstring
-        #~ self.reparseLoc = restartLoc
-
-class RecursiveGrammarException(Exception):
-    """exception thrown by C{validate()} if the grammar could be improperly recursive"""
-    def __init__( self, parseElementList ):
-        self.parseElementTrace = parseElementList
-
-    def __str__( self ):
-        return "RecursiveGrammarException: %s" % self.parseElementTrace
-
-class _ParseResultsWithOffset(object):
-    def __init__(self,p1,p2):
-        self.tup = (p1,p2)
-    def __getitem__(self,i):
-        return self.tup[i]
-    def __repr__(self):
-        return repr(self.tup)
-    def setOffset(self,i):
-        self.tup = (self.tup[0],i)
-
-class ParseResults(object):
-    """Structured parse results, to provide multiple means of access to the parsed data:
-       - as a list (C{len(results)})
-       - by list index (C{results[0], results[1]}, etc.)
-       - by attribute (C{results.<resultsName>})
-       """
-    #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" )
-    def __new__(cls, toklist, name=None, asList=True, modal=True ):
-        if isinstance(toklist, cls):
-            return toklist
-        retobj = object.__new__(cls)
-        retobj.__doinit = True
-        return retobj
-
-    # Performance tuning: we construct a *lot* of these, so keep this
-    # constructor as small and fast as possible
-    def __init__( self, toklist, name=None, asList=True, modal=True, isinstance=isinstance ):
-        if self.__doinit:
-            self.__doinit = False
-            self.__name = None
-            self.__parent = None
-            self.__accumNames = {}
-            if isinstance(toklist, list):
-                self.__toklist = toklist[:]
-            else:
-                self.__toklist = [toklist]
-            self.__tokdict = dict()
-
-        if name is not None and name:
-            if not modal:
-                self.__accumNames[name] = 0
-            if isinstance(name,int):
-                name = _ustr(name) # will always return a str, but use _ustr for consistency
-            self.__name = name
-            if not toklist in (None,'',[]):
-                if isinstance(toklist,basestring):
-                    toklist = [ toklist ]
-                if asList:
-                    if isinstance(toklist,ParseResults):
-                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
-                    else:
-                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
-                    self[name].__name = name
-                else:
-                    try:
-                        self[name] = toklist[0]
-                    except (KeyError,TypeError,IndexError):
-                        self[name] = toklist
-
-    def __getitem__( self, i ):
-        if isinstance( i, (int,slice) ):
-            return self.__toklist[i]
-        else:
-            if i not in self.__accumNames:
-                return self.__tokdict[i][-1][0]
-            else:
-                return ParseResults([ v[0] for v in self.__tokdict[i] ])
-
-    def __setitem__( self, k, v, isinstance=isinstance ):
-        if isinstance(v,_ParseResultsWithOffset):
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
-            sub = v[0]
-        elif isinstance(k,int):
-            self.__toklist[k] = v
-            sub = v
-        else:
-            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
-            sub = v
-        if isinstance(sub,ParseResults):
-            sub.__parent = wkref(self)
-
-    def __delitem__( self, i ):
-        if isinstance(i,(int,slice)):
-            mylen = len( self.__toklist )
-            del self.__toklist[i]
-
-            # convert int to slice
-            if isinstance(i, int):
-                if i < 0:
-                    i += mylen
-                i = slice(i, i+1)
-            # get removed indices
-            removed = list(range(*i.indices(mylen)))
-            removed.reverse()
-            # fixup indices in token dictionary
-            for name in self.__tokdict:
-                occurrences = self.__tokdict[name]
-                for j in removed:
-                    for k, (value, position) in enumerate(occurrences):
-                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
-        else:
-            del self.__tokdict[i]
-
-    def __contains__( self, k ):
-        return k in self.__tokdict
-
-    def __len__( self ): return len( self.__toklist )
-    def __bool__(self): return len( self.__toklist ) > 0
-    __nonzero__ = __bool__
-    def __iter__( self ): return iter( self.__toklist )
-    def __reversed__( self ): return iter( self.__toklist[::-1] )
-    def keys( self ):
-        """Returns all named result keys."""
-        return self.__tokdict.keys()
-
-    def pop( self, index=-1 ):
-        """Removes and returns item at specified index (default=last).
-           Will work with either numeric indices or dict-key indicies."""
-        ret = self[index]
-        del self[index]
-        return ret
-
-    def get(self, key, defaultValue=None):
-        """Returns named result matching the given key, or if there is no
-           such name, then returns the given C{defaultValue} or C{None} if no
-           C{defaultValue} is specified."""
-        if key in self:
-            return self[key]
-        else:
-            return defaultValue
-
-    def insert( self, index, insStr ):
-        """Inserts new element at location index in the list of parsed tokens."""
-        self.__toklist.insert(index, insStr)
-        # fixup indices in token dictionary
-        for name in self.__tokdict:
-            occurrences = self.__tokdict[name]
-            for k, (value, position) in enumerate(occurrences):
-                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
-
-    def items( self ):
-        """Returns all named result keys and values as a list of tuples."""
-        return [(k,self[k]) for k in self.__tokdict]
-
-    def values( self ):
-        """Returns all named result values."""
-        return [ v[-1][0] for v in self.__tokdict.values() ]
-
-    def __getattr__( self, name ):
-        if True: #name not in self.__slots__:
-            if name in self.__tokdict:
-                if name not in self.__accumNames:
-                    return self.__tokdict[name][-1][0]
-                else:
-                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
-            else:
-                return ""
-        return None
-
-    def __add__( self, other ):
-        ret = self.copy()
-        ret += other
-        return ret
-
-    def __iadd__( self, other ):
-        if other.__tokdict:
-            offset = len(self.__toklist)
-            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
-            otheritems = other.__tokdict.items()
-            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
-                                for (k,vlist) in otheritems for v in vlist]
-            for k,v in otherdictitems:
-                self[k] = v
-                if isinstance(v[0],ParseResults):
-                    v[0].__parent = wkref(self)
-            
-        self.__toklist += other.__toklist
-        self.__accumNames.update( other.__accumNames )
-        return self
-
-    def __radd__(self, other):
-        if isinstance(other,int) and other == 0:
-            return self.copy()
-        
-    def __repr__( self ):
-        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
-
-    def __str__( self ):
-        out = []
-        for i in self.__toklist:
-            if isinstance(i, ParseResults):
-                out.append(_ustr(i))
-            else:
-                out.append(repr(i))
-        return '[' + ', '.join(out) + ']'
-
-    def _asStringList( self, sep='' ):
-        out = []
-        for item in self.__toklist:
-            if out and sep:
-                out.append(sep)
-            if isinstance( item, ParseResults ):
-                out += item._asStringList()
-            else:
-                out.append( _ustr(item) )
-        return out
-
-    def asList( self ):
-        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
-        out = []
-        for res in self.__toklist:
-            if isinstance(res,ParseResults):
-                out.append( res.asList() )
-            else:
-                out.append( res )
-        return out
-
-    def asDict( self ):
-        """Returns the named parse results as dictionary."""
-        return dict( self.items() )
-
-    def copy( self ):
-        """Returns a new copy of a C{ParseResults} object."""
-        ret = ParseResults( self.__toklist )
-        ret.__tokdict = self.__tokdict.copy()
-        ret.__parent = self.__parent
-        ret.__accumNames.update( self.__accumNames )
-        ret.__name = self.__name
-        return ret
-
-    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
-        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
-        nl = "\n"
-        out = []
-        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items()
-                                                            for v in vlist ] )
-        nextLevelIndent = indent + "  "
-
-        # collapse out indents if formatting is not desired
-        if not formatted:
-            indent = ""
-            nextLevelIndent = ""
-            nl = ""
-
-        selfTag = None
-        if doctag is not None:
-            selfTag = doctag
-        else:
-            if self.__name:
-                selfTag = self.__name
-
-        if not selfTag:
-            if namedItemsOnly:
-                return ""
-            else:
-                selfTag = "ITEM"
-
-        out += [ nl, indent, "<", selfTag, ">" ]
-
-        worklist = self.__toklist
-        for i,res in enumerate(worklist):
-            if isinstance(res,ParseResults):
-                if i in namedItems:
-                    out += [ res.asXML(namedItems[i],
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-                else:
-                    out += [ res.asXML(None,
-                                        namedItemsOnly and doctag is None,
-                                        nextLevelIndent,
-                                        formatted)]
-            else:
-                # individual token, see if there is a name for it
-                resTag = None
-                if i in namedItems:
-                    resTag = namedItems[i]
-                if not resTag:
-                    if namedItemsOnly:
-                        continue
-                    else:
-                        resTag = "ITEM"
-                xmlBodyText = _xml_escape(_ustr(res))
-                out += [ nl, nextLevelIndent, "<", resTag, ">",
-                                                xmlBodyText,
-                                                "</", resTag, ">" ]
-
-        out += [ nl, indent, "</", selfTag, ">" ]
-        return "".join(out)
-
-    def __lookup(self,sub):
-        for k,vlist in self.__tokdict.items():
-            for v,loc in vlist:
-                if sub is v:
-                    return k
-        return None
-
-    def getName(self):
-        """Returns the results name for this token expression."""
-        if self.__name:
-            return self.__name
-        elif self.__parent:
-            par = self.__parent()
-            if par:
-                return par.__lookup(self)
-            else:
-                return None
-        elif (len(self) == 1 and
-               len(self.__tokdict) == 1 and
-               self.__tokdict.values()[0][0][1] in (0,-1)):
-            return self.__tokdict.keys()[0]
-        else:
-            return None
-
-    def dump(self,indent='',depth=0):
-        """Diagnostic method for listing out the contents of a C{ParseResults}.
-           Accepts an optional C{indent} argument so that this string can be embedded
-           in a nested display of other data."""
-        out = []
-        out.append( indent+_ustr(self.asList()) )
-        keys = self.items()
-        keys.sort()
-        for k,v in keys:
-            if out:
-                out.append('\n')
-            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
-            if isinstance(v,ParseResults):
-                if v.keys():
-                    out.append( v.dump(indent,depth+1) )
-                else:
-                    out.append(_ustr(v))
-            else:
-                out.append(_ustr(v))
-        return "".join(out)
-
-    # add support for pickle protocol
-    def __getstate__(self):
-        return ( self.__toklist,
-                 ( self.__tokdict.copy(),
-                   self.__parent is not None and self.__parent() or None,
-                   self.__accumNames,
-                   self.__name ) )
-
-    def __setstate__(self,state):
-        self.__toklist = state[0]
-        (self.__tokdict,
-         par,
-         inAccumNames,
-         self.__name) = state[1]
-        self.__accumNames = {}
-        self.__accumNames.update(inAccumNames)
-        if par is not None:
-            self.__parent = wkref(par)
-        else:
-            self.__parent = None
-
-    def __dir__(self):
-        return dir(super(ParseResults,self)) + list(self.keys())
-
-collections.MutableMapping.register(ParseResults)
-
-def col (loc,strg):
-    """Returns current column within a string, counting newlines as line separators.
-   The first column is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
-
-def lineno(loc,strg):
-    """Returns current line number within a string, counting newlines as line separators.
-   The first line is number 1.
-
-   Note: the default parsing behavior is to expand tabs in the input string
-   before starting the parsing process.  See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information
-   on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-   consistent view of the parsed string, the parse location, and line and column
-   positions within the parsed string.
-   """
-    return strg.count("\n",0,loc) + 1
-
-def line( loc, strg ):
-    """Returns the line of text containing loc within a string, counting newlines as line separators.
-       """
-    lastCR = strg.rfind("\n", 0, loc)
-    nextCR = strg.find("\n", loc)
-    if nextCR >= 0:
-        return strg[lastCR+1:nextCR]
-    else:
-        return strg[lastCR+1:]
-
-def _defaultStartDebugAction( instring, loc, expr ):
-    print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-
-def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
-    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
-
-def _defaultExceptionDebugAction( instring, loc, expr, exc ):
-    print ("Exception raised:" + _ustr(exc))
-
-def nullDebugAction(*args):
-    """'Do-nothing' debug action, to suppress debugging output during parsing."""
-    pass
-
-'decorator to trim function calls to match the arity of the target'
-def _trim_arity(func, maxargs=2):
-    if func in singleArgBuiltins:
-        return lambda s,l,t: func(t)
-    limit = maxargs
-    def wrapper(*args):
-        nonlocal limit
-        while 1:
-            try:
-                return func(*args[limit:])
-            except TypeError:
-                if limit:
-                    limit -= 1
-                    continue
-                raise
-    return wrapper
-    
-class ParserElement(object):
-    """Abstract base level parser element class."""
-    DEFAULT_WHITE_CHARS = " \n\t\r"
-    verbose_stacktrace = False
-
-    def setDefaultWhitespaceChars( chars ):
-        """Overrides the default whitespace chars
-        """
-        ParserElement.DEFAULT_WHITE_CHARS = chars
-    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
-
-    def inlineLiteralsUsing(cls):
-        """
-        Set class to be used for inclusion of string literals into a parser.
-        """
-        ParserElement.literalStringClass = cls
-    inlineLiteralsUsing = staticmethod(inlineLiteralsUsing)
-
-    def __init__( self, savelist=False ):
-        self.parseAction = list()
-        self.failAction = None
-        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
-        self.strRepr = None
-        self.resultsName = None
-        self.saveAsList = savelist
-        self.skipWhitespace = True
-        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        self.copyDefaultWhiteChars = True
-        self.mayReturnEmpty = False # used when checking for left-recursion
-        self.keepTabs = False
-        self.ignoreExprs = list()
-        self.debug = False
-        self.streamlined = False
-        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
-        self.errmsg = ""
-        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
-        self.debugActions = ( None, None, None ) #custom debug actions
-        self.re = None
-        self.callPreparse = True # used to avoid redundant calls to preParse
-        self.callDuringTry = False
-
-    def copy( self ):
-        """Make a copy of this C{ParserElement}.  Useful for defining different parse actions
-           for the same parsing pattern, using copies of the original parse element."""
-        cpy = copy.copy( self )
-        cpy.parseAction = self.parseAction[:]
-        cpy.ignoreExprs = self.ignoreExprs[:]
-        if self.copyDefaultWhiteChars:
-            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
-        return cpy
-
-    def setName( self, name ):
-        """Define name for this expression, for use in debugging."""
-        self.name = name
-        self.errmsg = "Expected " + self.name
-        if hasattr(self,"exception"):
-            self.exception.msg = self.errmsg
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        """Define name for referencing matching tokens as a nested attribute
-           of the returned parse results.
-           NOTE: this returns a *copy* of the original C{ParserElement} object;
-           this is so that the client can define a basic element, such as an
-           integer, and reference it in multiple places with different names.
-           
-           You can also set results names using the abbreviated syntax,
-           C{expr("name")} in place of C{expr.setResultsName("name")} - 
-           see L{I{__call__}<__call__>}.
-        """
-        newself = self.copy()
-        if name.endswith("*"):
-            name = name[:-1]
-            listAllMatches=True
-        newself.resultsName = name
-        newself.modalResults = not listAllMatches
-        return newself
-
-    def setBreak(self,breakFlag = True):
-        """Method to invoke the Python pdb debugger when this element is
-           about to be parsed. Set C{breakFlag} to True to enable, False to
-           disable.
-        """
-        if breakFlag:
-            _parseMethod = self._parse
-            def breaker(instring, loc, doActions=True, callPreParse=True):
-                import pdb
-                pdb.set_trace()
-                return _parseMethod( instring, loc, doActions, callPreParse )
-            breaker._originalParseMethod = _parseMethod
-            self._parse = breaker
-        else:
-            if hasattr(self._parse,"_originalParseMethod"):
-                self._parse = self._parse._originalParseMethod
-        return self
-
-    def setParseAction( self, *fns, **kwargs ):
-        """Define action to perform when successfully matching parse element definition.
-           Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
-           C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
-            - s   = the original string being parsed (see note below)
-            - loc = the location of the matching substring
-            - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object
-           If the functions in fns modify the tokens, they can return them as the return
-           value from fn, and the modified list of tokens will replace the original.
-           Otherwise, fn does not need to return any value.
-
-           Note: the default parsing behavior is to expand tabs in the input string
-           before starting the parsing process.  See L{I{parseString}<parseString>} for more information
-           on parsing strings containing C{<TAB>}s, and suggested methods to maintain a
-           consistent view of the parsed string, the parse location, and line and column
-           positions within the parsed string.
-           """
-        self.parseAction = list(map(_trim_arity, list(fns)))
-        self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def addParseAction( self, *fns, **kwargs ):
-        """Add parse action to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}."""
-        self.parseAction += list(map(_trim_arity, list(fns)))
-        self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"])
-        return self
-
-    def setFailAction( self, fn ):
-        """Define action to perform if parsing fails at this expression.
-           Fail acton fn is a callable function that takes the arguments
-           C{fn(s,loc,expr,err)} where:
-            - s = string being parsed
-            - loc = location where expression match was attempted and failed
-            - expr = the parse expression that failed
-            - err = the exception thrown
-           The function returns no value.  It may throw C{L{ParseFatalException}}
-           if it is desired to stop parsing immediately."""
-        self.failAction = fn
-        return self
-
-    def _skipIgnorables( self, instring, loc ):
-        exprsFound = True
-        while exprsFound:
-            exprsFound = False
-            for e in self.ignoreExprs:
-                try:
-                    while 1:
-                        loc,dummy = e._parse( instring, loc )
-                        exprsFound = True
-                except ParseException:
-                    pass
-        return loc
-
-    def preParse( self, instring, loc ):
-        if self.ignoreExprs:
-            loc = self._skipIgnorables( instring, loc )
-
-        if self.skipWhitespace:
-            wt = self.whiteChars
-            instrlen = len(instring)
-            while loc < instrlen and instring[loc] in wt:
-                loc += 1
-
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        return loc, []
-
-    def postParse( self, instring, loc, tokenlist ):
-        return tokenlist
-
-    #~ @profile
-    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
-        debugging = ( self.debug ) #and doActions )
-
-        if debugging or self.failAction:
-            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
-            if (self.debugActions[0] ):
-                self.debugActions[0]( instring, loc, self )
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            try:
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            except ParseBaseException as err:
-                #~ print ("Exception raised:", err)
-                if self.debugActions[2]:
-                    self.debugActions[2]( instring, tokensStart, self, err )
-                if self.failAction:
-                    self.failAction( instring, tokensStart, self, err )
-                raise
-        else:
-            if callPreParse and self.callPreparse:
-                preloc = self.preParse( instring, loc )
-            else:
-                preloc = loc
-            tokensStart = preloc
-            if self.mayIndexError or loc >= len(instring):
-                try:
-                    loc,tokens = self.parseImpl( instring, preloc, doActions )
-                except IndexError:
-                    raise ParseException( instring, len(instring), self.errmsg, self )
-            else:
-                loc,tokens = self.parseImpl( instring, preloc, doActions )
-
-        tokens = self.postParse( instring, loc, tokens )
-
-        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
-        if self.parseAction and (doActions or self.callDuringTry):
-            if debugging:
-                try:
-                    for fn in self.parseAction:
-                        tokens = fn( instring, tokensStart, retTokens )
-                        if tokens is not None:
-                            retTokens = ParseResults( tokens,
-                                                      self.resultsName,
-                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                      modal=self.modalResults )
-                except ParseBaseException as err:
-                    #~ print "Exception raised in user parse action:", err
-                    if (self.debugActions[2] ):
-                        self.debugActions[2]( instring, tokensStart, self, err )
-                    raise
-            else:
-                for fn in self.parseAction:
-                    tokens = fn( instring, tokensStart, retTokens )
-                    if tokens is not None:
-                        retTokens = ParseResults( tokens,
-                                                  self.resultsName,
-                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
-                                                  modal=self.modalResults )
-
-        if debugging:
-            #~ print ("Matched",self,"->",retTokens.asList())
-            if (self.debugActions[1] ):
-                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
-
-        return loc, retTokens
-
-    def tryParse( self, instring, loc ):
-        try:
-            return self._parse( instring, loc, doActions=False )[0]
-        except ParseFatalException:
-            raise ParseException( instring, loc, self.errmsg, self)
-
-    # this method gets repeatedly called during backtracking with the same arguments -
-    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
-    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
-        lookup = (self,instring,loc,callPreParse,doActions)
-        if lookup in ParserElement._exprArgCache:
-            value = ParserElement._exprArgCache[ lookup ]
-            if isinstance(value, Exception):
-                raise value
-            return (value[0],value[1].copy())
-        else:
-            try:
-                value = self._parseNoCache( instring, loc, doActions, callPreParse )
-                ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy())
-                return value
-            except ParseBaseException as pe:
-                pe.__traceback__ = None
-                ParserElement._exprArgCache[ lookup ] = pe
-                raise
-
-    _parse = _parseNoCache
-
-    # argument cache for optimizing repeated calls when backtracking through recursive expressions
-    _exprArgCache = {}
-    def resetCache():
-        ParserElement._exprArgCache.clear()
-    resetCache = staticmethod(resetCache)
-
-    _packratEnabled = False
-    def enablePackrat():
-        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
-           Repeated parse attempts at the same string location (which happens
-           often in many complex grammars) can immediately return a cached value,
-           instead of re-executing parsing/validating code.  Memoizing is done of
-           both valid results and parsing exceptions.
-
-           This speedup may break existing programs that use parse actions that
-           have side-effects.  For this reason, packrat parsing is disabled when
-           you first import pyparsing.  To activate the packrat feature, your
-           program must call the class method C{ParserElement.enablePackrat()}.  If
-           your program uses C{psyco} to "compile as you go", you must call
-           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,
-           Python will crash.  For best results, call C{enablePackrat()} immediately
-           after importing pyparsing.
-        """
-        if not ParserElement._packratEnabled:
-            ParserElement._packratEnabled = True
-            ParserElement._parse = ParserElement._parseCache
-    enablePackrat = staticmethod(enablePackrat)
-
-    def parseString( self, instring, parseAll=False ):
-        """Execute the parse expression with the given string.
-           This is the main interface to the client code, once the complete
-           expression has been built.
-
-           If you want the grammar to require that the entire input string be
-           successfully parsed, then set C{parseAll} to True (equivalent to ending
-           the grammar with C{L{StringEnd()}}).
-
-           Note: C{parseString} implicitly calls C{expandtabs()} on the input string,
-           in order to report proper column numbers in parse actions.
-           If the input string contains tabs and
-           the grammar uses parse actions that use the C{loc} argument to index into the
-           string being parsed, you can ensure you have a consistent view of the input
-           string by:
-            - calling C{parseWithTabs} on your grammar before calling C{parseString}
-              (see L{I{parseWithTabs}<parseWithTabs>})
-            - define your parse action using the full C{(s,loc,toks)} signature, and
-              reference the input string using the parse action's C{s} argument
-            - explictly expand the tabs in your input string before calling
-              C{parseString}
-        """
-        ParserElement.resetCache()
-        if not self.streamlined:
-            self.streamline()
-            #~ self.saveAsList = True
-        for e in self.ignoreExprs:
-            e.streamline()
-        if not self.keepTabs:
-            instring = instring.expandtabs()
-        try:
-            loc, tokens = self._parse( instring, 0 )
-            if parseAll:
-                loc = self.preParse( instring, loc )
-                se = Empty() + StringEnd()
-                se._parse( instring, loc )
-        except ParseBaseException as exc:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                raise exc
-        else:
-            return tokens
-
-    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
-        """Scan the input string for expression matches.  Each match will return the
-           matching tokens, start location, and end location.  May be called with optional
-           C{maxMatches} argument, to clip scanning after 'n' matches are found.  If
-           C{overlap} is specified, then overlapping matches will be reported.
-
-           Note that the start and end locations are reported relative to the string
-           being parsed.  See L{I{parseString}<parseString>} for more information on parsing
-           strings with embedded tabs."""
-        if not self.streamlined:
-            self.streamline()
-        for e in self.ignoreExprs:
-            e.streamline()
-
-        if not self.keepTabs:
-            instring = _ustr(instring).expandtabs()
-        instrlen = len(instring)
-        loc = 0
-        preparseFn = self.preParse
-        parseFn = self._parse
-        ParserElement.resetCache()
-        matches = 0
-        try:
-            while loc <= instrlen and matches < maxMatches:
-                try:
-                    preloc = preparseFn( instring, loc )
-                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
-                except ParseException:
-                    loc = preloc+1
-                else:
-                    if nextLoc > loc:
-                        matches += 1
-                        yield tokens, preloc, nextLoc
-                        if overlap:
-                            nextloc = preparseFn( instring, loc )
-                            if nextloc > loc:
-                                loc = nextLoc
-                            else:
-                                loc += 1
-                        else:
-                            loc = nextLoc
-                    else:
-                        loc = preloc+1
-        except ParseBaseException as exc:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                raise exc
-
-    def transformString( self, instring ):
-        """Extension to C{L{scanString}}, to modify matching text with modified tokens that may
-           be returned from a parse action.  To use C{transformString}, define a grammar and
-           attach a parse action to it that modifies the returned token list.
-           Invoking C{transformString()} on a target string will then scan for matches,
-           and replace the matched text patterns according to the logic in the parse
-           action.  C{transformString()} returns the resulting transformed string."""
-        out = []
-        lastE = 0
-        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
-        # keep string locs straight between transformString and scanString
-        self.keepTabs = True
-        try:
-            for t,s,e in self.scanString( instring ):
-                out.append( instring[lastE:s] )
-                if t:
-                    if isinstance(t,ParseResults):
-                        out += t.asList()
-                    elif isinstance(t,list):
-                        out += t
-                    else:
-                        out.append(t)
-                lastE = e
-            out.append(instring[lastE:])
-            out = [o for o in out if o]
-            return "".join(map(_ustr,_flatten(out)))
-        except ParseBaseException as exc:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                raise exc
-
-    def searchString( self, instring, maxMatches=_MAX_INT ):
-        """Another extension to C{L{scanString}}, simplifying the access to the tokens found
-           to match the given parse expression.  May be called with optional
-           C{maxMatches} argument, to clip searching after 'n' matches are found.
-        """
-        try:
-            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
-        except ParseBaseException as exc:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                raise exc
-
-    def __add__(self, other ):
-        """Implementation of + operator - returns C{L{And}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, other ] )
-
-    def __radd__(self, other ):
-        """Implementation of + operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other + self
-
-    def __sub__(self, other):
-        """Implementation of - operator, returns C{L{And}} with error stop"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return And( [ self, And._ErrorStop(), other ] )
-
-    def __rsub__(self, other ):
-        """Implementation of - operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other - self
-
-    def __mul__(self,other):
-        """Implementation of * operator, allows use of C{expr * 3} in place of
-           C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer
-           tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples
-           may also include C{None} as in:
-            - C{expr*(n,None)} or C{expr*(n,)} is equivalent
-              to C{expr*n + L{ZeroOrMore}(expr)}
-              (read as "at least n instances of C{expr}")
-            - C{expr*(None,n)} is equivalent to C{expr*(0,n)}
-              (read as "0 to n instances of C{expr}")
-            - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}
-            - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}
-
-           Note that C{expr*(None,n)} does not raise an exception if
-           more than n exprs exist in the input stream; that is,
-           C{expr*(None,n)} does not enforce a maximum number of expr
-           occurrences.  If this behavior is desired, then write
-           C{expr*(None,n) + ~expr}
-
-        """
-        if isinstance(other,int):
-            minElements, optElements = other,0
-        elif isinstance(other,tuple):
-            other = (other + (None, None))[:2]
-            if other[0] is None:
-                other = (0, other[1])
-            if isinstance(other[0],int) and other[1] is None:
-                if other[0] == 0:
-                    return ZeroOrMore(self)
-                if other[0] == 1:
-                    return OneOrMore(self)
-                else:
-                    return self*other[0] + ZeroOrMore(self)
-            elif isinstance(other[0],int) and isinstance(other[1],int):
-                minElements, optElements = other
-                optElements -= minElements
-            else:
-                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
-        else:
-            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
-
-        if minElements < 0:
-            raise ValueError("cannot multiply ParserElement by negative value")
-        if optElements < 0:
-            raise ValueError("second tuple value must be greater or equal to first tuple value")
-        if minElements == optElements == 0:
-            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
-
-        if (optElements):
-            def makeOptionalList(n):
-                if n>1:
-                    return Optional(self + makeOptionalList(n-1))
-                else:
-                    return Optional(self)
-            if minElements:
-                if minElements == 1:
-                    ret = self + makeOptionalList(optElements)
-                else:
-                    ret = And([self]*minElements) + makeOptionalList(optElements)
-            else:
-                ret = makeOptionalList(optElements)
-        else:
-            if minElements == 1:
-                ret = self
-            else:
-                ret = And([self]*minElements)
-        return ret
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-
-    def __or__(self, other ):
-        """Implementation of | operator - returns C{L{MatchFirst}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return MatchFirst( [ self, other ] )
-
-    def __ror__(self, other ):
-        """Implementation of | operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other | self
-
-    def __xor__(self, other ):
-        """Implementation of ^ operator - returns C{L{Or}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Or( [ self, other ] )
-
-    def __rxor__(self, other ):
-        """Implementation of ^ operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other ^ self
-
-    def __and__(self, other ):
-        """Implementation of & operator - returns C{L{Each}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return Each( [ self, other ] )
-
-    def __rand__(self, other ):
-        """Implementation of & operator when left operand is not a C{L{ParserElement}}"""
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        if not isinstance( other, ParserElement ):
-            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
-                    SyntaxWarning, stacklevel=2)
-            return None
-        return other & self
-
-    def __invert__( self ):
-        """Implementation of ~ operator - returns C{L{NotAny}}"""
-        return NotAny( self )
-
-    def __call__(self, name):
-        """Shortcut for C{L{setResultsName}}, with C{listAllMatches=default}::
-             userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
-           could be written as::
-             userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
-             
-           If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be
-           passed as C{True}.
-           """
-        return self.setResultsName(name)
-
-    def suppress( self ):
-        """Suppresses the output of this C{ParserElement}; useful to keep punctuation from
-           cluttering up returned output.
-        """
-        return Suppress( self )
-
-    def leaveWhitespace( self ):
-        """Disables the skipping of whitespace before matching the characters in the
-           C{ParserElement}'s defined pattern.  This is normally only used internally by
-           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
-        """
-        self.skipWhitespace = False
-        return self
-
-    def setWhitespaceChars( self, chars ):
-        """Overrides the default whitespace chars
-        """
-        self.skipWhitespace = True
-        self.whiteChars = chars
-        self.copyDefaultWhiteChars = False
-        return self
-
-    def parseWithTabs( self ):
-        """Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string.
-           Must be called before C{parseString} when the input grammar contains elements that
-           match C{<TAB>} characters."""
-        self.keepTabs = True
-        return self
-
-    def ignore( self, other ):
-        """Define expression to be ignored (e.g., comments) while doing pattern
-           matching; may be called repeatedly, to define multiple comment or other
-           ignorable patterns.
-        """
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                self.ignoreExprs.append( other.copy() )
-        else:
-            self.ignoreExprs.append( Suppress( other.copy() ) )
-        return self
-
-    def setDebugActions( self, startAction, successAction, exceptionAction ):
-        """Enable display of debugging messages while doing pattern matching."""
-        self.debugActions = (startAction or _defaultStartDebugAction,
-                             successAction or _defaultSuccessDebugAction,
-                             exceptionAction or _defaultExceptionDebugAction)
-        self.debug = True
-        return self
-
-    def setDebug( self, flag=True ):
-        """Enable display of debugging messages while doing pattern matching.
-           Set C{flag} to True to enable, False to disable."""
-        if flag:
-            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
-        else:
-            self.debug = False
-        return self
-
-    def __str__( self ):
-        return self.name
-
-    def __repr__( self ):
-        return _ustr(self)
-
-    def streamline( self ):
-        self.streamlined = True
-        self.strRepr = None
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        pass
-
-    def validate( self, validateTrace=[] ):
-        """Check defined expressions for valid structure, check for infinite recursive definitions."""
-        self.checkRecursion( [] )
-
-    def parseFile( self, file_or_filename, parseAll=False ):
-        """Execute the parse expression on the given file or filename.
-           If a filename is specified (instead of a file object),
-           the entire file is opened, read, and closed before parsing.
-        """
-        try:
-            file_contents = file_or_filename.read()
-        except AttributeError:
-            f = open(file_or_filename, "r")
-            file_contents = f.read()
-            f.close()
-        try:
-            return self.parseString(file_contents, parseAll)
-        except ParseBaseException as exc:
-            if ParserElement.verbose_stacktrace:
-                raise
-            else:
-                # catch and re-raise exception from here, clears out pyparsing internal stack trace
-                raise exc
-
-    def __eq__(self,other):
-        if isinstance(other, ParserElement):
-            return self is other or self.__dict__ == other.__dict__
-        elif isinstance(other, basestring):
-            try:
-                self.parseString(_ustr(other), parseAll=True)
-                return True
-            except ParseBaseException:
-                return False
-        else:
-            return super(ParserElement,self)==other
-
-    def __ne__(self,other):
-        return not (self == other)
-
-    def __hash__(self):
-        return hash(id(self))
-
-    def __req__(self,other):
-        return self == other
-
-    def __rne__(self,other):
-        return not (self == other)
-
-
-class Token(ParserElement):
-    """Abstract C{ParserElement} subclass, for defining atomic matching patterns."""
-    def __init__( self ):
-        super(Token,self).__init__( savelist=False )
-
-    def setName(self, name):
-        s = super(Token,self).setName(name)
-        self.errmsg = "Expected " + self.name
-        return s
-
-
-class Empty(Token):
-    """An empty token, will always match."""
-    def __init__( self ):
-        super(Empty,self).__init__()
-        self.name = "Empty"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-
-class NoMatch(Token):
-    """A token that will never match."""
-    def __init__( self ):
-        super(NoMatch,self).__init__()
-        self.name = "NoMatch"
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.errmsg = "Unmatchable token"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        raise ParseException(instring, loc, self.errmsg, self)
-
-
-class Literal(Token):
-    """Token to exactly match a specified string."""
-    def __init__( self, matchString ):
-        super(Literal,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Literal; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-            self.__class__ = Empty
-        self.name = '"%s"' % _ustr(self.match)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-
-    # Performance tuning: this routine gets called a *lot*
-    # if this is a single character match string  and the first character matches,
-    # short-circuit as quickly as possible, and avoid calling startswith
-    #~ @profile
-    def parseImpl( self, instring, loc, doActions=True ):
-        if (instring[loc] == self.firstMatchChar and
-            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
-            return loc+self.matchLen, self.match
-        raise ParseException(instring, loc, self.errmsg, self)
-_L = Literal
-ParserElement.literalStringClass = Literal
-
-class Keyword(Token):
-    """Token to exactly match a specified string as a keyword, that is, it must be
-       immediately followed by a non-keyword character.  Compare with C{L{Literal}}::
-         Literal("if") will match the leading C{'if'} in C{'ifAndOnlyIf'}.
-         Keyword("if") will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}
-       Accepts two optional constructor arguments in addition to the keyword string:
-       C{identChars} is a string of characters that would be valid identifier characters,
-       defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive
-       matching, default is C{False}.
-    """
-    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
-
-    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
-        super(Keyword,self).__init__()
-        self.match = matchString
-        self.matchLen = len(matchString)
-        try:
-            self.firstMatchChar = matchString[0]
-        except IndexError:
-            warnings.warn("null string passed to Keyword; use Empty() instead",
-                            SyntaxWarning, stacklevel=2)
-        self.name = '"%s"' % self.match
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = False
-        self.mayIndexError = False
-        self.caseless = caseless
-        if caseless:
-            self.caselessmatch = matchString.upper()
-            identChars = identChars.upper()
-        self.identChars = set(identChars)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.caseless:
-            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
-                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        else:
-            if (instring[loc] == self.firstMatchChar and
-                (self.matchLen==1 or instring.startswith(self.match,loc)) and
-                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
-                (loc == 0 or instring[loc-1] not in self.identChars) ):
-                return loc+self.matchLen, self.match
-        raise ParseException(instring, loc, self.errmsg, self)
-
-    def copy(self):
-        c = super(Keyword,self).copy()
-        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
-        return c
-
-    def setDefaultKeywordChars( chars ):
-        """Overrides the default Keyword chars
-        """
-        Keyword.DEFAULT_KEYWORD_CHARS = chars
-    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)
-
-class CaselessLiteral(Literal):
-    """Token to match a specified string, ignoring case of letters.
-       Note: the matched results will always be in the case of the given
-       match string, NOT the case of the input text.
-    """
-    def __init__( self, matchString ):
-        super(CaselessLiteral,self).__init__( matchString.upper() )
-        # Preserve the defining literal.
-        self.returnString = matchString
-        self.name = "'%s'" % self.returnString
-        self.errmsg = "Expected " + self.name
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[ loc:loc+self.matchLen ].upper() == self.match:
-            return loc+self.matchLen, self.returnString
-        raise ParseException(instring, loc, self.errmsg, self)
-
-class CaselessKeyword(Keyword):
-    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
-        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
-             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
-            return loc+self.matchLen, self.match
-        raise ParseException(instring, loc, self.errmsg, self)
-
-class Word(Token):
-    """Token for matching words composed of allowed character sets.
-       Defined with string containing all allowed initial characters,
-       an optional string containing allowed body characters (if omitted,
-       defaults to the initial character set), and an optional minimum,
-       maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction. An optional
-       C{exclude} parameter can list characters that might be found in 
-       the input C{bodyChars} string; useful to define a word of all printables
-       except for one or two characters, for instance.
-    """
-    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
-        super(Word,self).__init__()
-        if excludeChars:
-            initChars = ''.join([c for c in initChars if c not in excludeChars])
-            if bodyChars:
-                bodyChars = ''.join([c for c in bodyChars if c not in excludeChars])
-        self.initCharsOrig = initChars
-        self.initChars = set(initChars)
-        if bodyChars :
-            self.bodyCharsOrig = bodyChars
-            self.bodyChars = set(bodyChars)
-        else:
-            self.bodyCharsOrig = initChars
-            self.bodyChars = set(initChars)
-
-        self.maxSpecified = max > 0
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.asKeyword = asKeyword
-
-        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
-            if self.bodyCharsOrig == self.initCharsOrig:
-                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
-            elif len(self.bodyCharsOrig) == 1:
-                self.reString = "%s[%s]*" % \
-                                      (re.escape(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            else:
-                self.reString = "[%s][%s]*" % \
-                                      (_escapeRegexRangeChars(self.initCharsOrig),
-                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
-            if self.asKeyword:
-                self.reString = r"\b"+self.reString+r"\b"
-            try:
-                self.re = re.compile( self.reString )
-            except:
-                self.re = None
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.re:
-            result = self.re.match(instring,loc)
-            if not result:
-                raise ParseException(instring, loc, self.errmsg, self)
-
-            loc = result.end()
-            return loc, result.group()
-
-        if not(instring[ loc ] in self.initChars):
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        start = loc
-        loc += 1
-        instrlen = len(instring)
-        bodychars = self.bodyChars
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, instrlen )
-        while loc < maxloc and instring[loc] in bodychars:
-            loc += 1
-
-        throwException = False
-        if loc - start < self.minLen:
-            throwException = True
-        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
-            throwException = True
-        if self.asKeyword:
-            if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars):
-                throwException = True
-
-        if throwException:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(Word,self).__str__()
-        except:
-            pass
-
-
-        if self.strRepr is None:
-
-            def charsAsStr(s):
-                if len(s)>4:
-                    return s[:4]+"..."
-                else:
-                    return s
-
-            if ( self.initCharsOrig != self.bodyCharsOrig ):
-                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
-            else:
-                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
-
-        return self.strRepr
-
-
-class Regex(Token):
-    """Token for matching strings that match a given regular expression.
-       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
-    """
-    compiledREtype = type(re.compile("[A-Z]"))
-    def __init__( self, pattern, flags=0):
-        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""
-        super(Regex,self).__init__()
-
-        if isinstance(pattern, basestring):
-            if len(pattern) == 0:
-                warnings.warn("null string passed to Regex; use Empty() instead",
-                        SyntaxWarning, stacklevel=2)
-
-            self.pattern = pattern
-            self.flags = flags
-
-            try:
-                self.re = re.compile(self.pattern, self.flags)
-                self.reString = self.pattern
-            except sre_constants.error:
-                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
-                    SyntaxWarning, stacklevel=2)
-                raise
-
-        elif isinstance(pattern, Regex.compiledREtype):
-            self.re = pattern
-            self.pattern = \
-            self.reString = str(pattern)
-            self.flags = flags
-            
-        else:
-            raise ValueError("Regex may only be constructed with a string or a compiled RE object")
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = self.re.match(instring,loc)
-        if not result:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        loc = result.end()
-        d = result.groupdict()
-        ret = ParseResults(result.group())
-        if d:
-            for k in d:
-                ret[k] = d[k]
-        return loc,ret
-
-    def __str__( self ):
-        try:
-            return super(Regex,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "Re:(%s)" % repr(self.pattern)
-
-        return self.strRepr
-
-
-class QuotedString(Token):
-    """Token for matching strings that are delimited by quoting characters.
-    """
-    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
-        """
-           Defined with the following parameters:
-            - quoteChar - string of one or more characters defining the quote delimiting string
-            - escChar - character to escape quotes, typically backslash (default=None)
-            - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
-            - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})
-            - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})
-            - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)
-        """
-        super(QuotedString,self).__init__()
-
-        # remove white space from quote chars - wont work anyway
-        quoteChar = quoteChar.strip()
-        if len(quoteChar) == 0:
-            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-            raise SyntaxError()
-
-        if endQuoteChar is None:
-            endQuoteChar = quoteChar
-        else:
-            endQuoteChar = endQuoteChar.strip()
-            if len(endQuoteChar) == 0:
-                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
-                raise SyntaxError()
-
-        self.quoteChar = quoteChar
-        self.quoteCharLen = len(quoteChar)
-        self.firstQuoteChar = quoteChar[0]
-        self.endQuoteChar = endQuoteChar
-        self.endQuoteCharLen = len(endQuoteChar)
-        self.escChar = escChar
-        self.escQuote = escQuote
-        self.unquoteResults = unquoteResults
-
-        if multiline:
-            self.flags = re.MULTILINE | re.DOTALL
-            self.pattern = r'%s(?:[^%s%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        else:
-            self.flags = 0
-            self.pattern = r'%s(?:[^%s\n\r%s]' % \
-                ( re.escape(self.quoteChar),
-                  _escapeRegexRangeChars(self.endQuoteChar[0]),
-                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
-        if len(self.endQuoteChar) > 1:
-            self.pattern += (
-                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
-                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
-                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
-                )
-        if escQuote:
-            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
-        if escChar:
-            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
-            charset = ''.join(set(self.quoteChar[0]+self.endQuoteChar[0])).replace('^',r'\^').replace('-',r'\-')
-            self.escCharReplacePattern = re.escape(self.escChar)+("([%s])" % charset)
-        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
-
-        try:
-            self.re = re.compile(self.pattern, self.flags)
-            self.reString = self.pattern
-        except sre_constants.error:
-            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
-                SyntaxWarning, stacklevel=2)
-            raise
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayIndexError = False
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
-        if not result:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        loc = result.end()
-        ret = result.group()
-
-        if self.unquoteResults:
-
-            # strip off quotes
-            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
-
-            if isinstance(ret,basestring):
-                # replace escaped characters
-                if self.escChar:
-                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
-
-                # replace escaped quotes
-                if self.escQuote:
-                    ret = ret.replace(self.escQuote, self.endQuoteChar)
-
-        return loc, ret
-
-    def __str__( self ):
-        try:
-            return super(QuotedString,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
-
-        return self.strRepr
-
-
-class CharsNotIn(Token):
-    """Token for matching words composed of characters *not* in a given set.
-       Defined with string containing all disallowed characters, and an optional
-       minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a
-       minimum value < 1 is not valid); the default values for C{max} and C{exact}
-       are 0, meaning no maximum or exact length restriction.
-    """
-    def __init__( self, notChars, min=1, max=0, exact=0 ):
-        super(CharsNotIn,self).__init__()
-        self.skipWhitespace = False
-        self.notChars = notChars
-
-        if min < 1:
-            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-        self.name = _ustr(self)
-        self.errmsg = "Expected " + self.name
-        self.mayReturnEmpty = ( self.minLen == 0 )
-        self.mayIndexError = False
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if instring[loc] in self.notChars:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        start = loc
-        loc += 1
-        notchars = self.notChars
-        maxlen = min( start+self.maxLen, len(instring) )
-        while loc < maxlen and \
-              (instring[loc] not in notchars):
-            loc += 1
-
-        if loc - start < self.minLen:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        return loc, instring[start:loc]
-
-    def __str__( self ):
-        try:
-            return super(CharsNotIn, self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            if len(self.notChars) > 4:
-                self.strRepr = "!W:(%s...)" % self.notChars[:4]
-            else:
-                self.strRepr = "!W:(%s)" % self.notChars
-
-        return self.strRepr
-
-class White(Token):
-    """Special matching class for matching whitespace.  Normally, whitespace is ignored
-       by pyparsing grammars.  This class is included when some whitespace structures
-       are significant.  Define with a string containing the whitespace characters to be
-       matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,
-       as defined for the C{L{Word}} class."""
-    whiteStrs = {
-        " " : "<SPC>",
-        "\t": "<TAB>",
-        "\n": "<LF>",
-        "\r": "<CR>",
-        "\f": "<FF>",
-        }
-    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
-        super(White,self).__init__()
-        self.matchWhite = ws
-        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
-        #~ self.leaveWhitespace()
-        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
-        self.mayReturnEmpty = True
-        self.errmsg = "Expected " + self.name
-
-        self.minLen = min
-
-        if max > 0:
-            self.maxLen = max
-        else:
-            self.maxLen = _MAX_INT
-
-        if exact > 0:
-            self.maxLen = exact
-            self.minLen = exact
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not(instring[ loc ] in self.matchWhite):
-            raise ParseException(instring, loc, self.errmsg, self)
-        start = loc
-        loc += 1
-        maxloc = start + self.maxLen
-        maxloc = min( maxloc, len(instring) )
-        while loc < maxloc and instring[loc] in self.matchWhite:
-            loc += 1
-
-        if loc - start < self.minLen:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-        return loc, instring[start:loc]
-
-
-class _PositionToken(Token):
-    def __init__( self ):
-        super(_PositionToken,self).__init__()
-        self.name=self.__class__.__name__
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-
-class GoToColumn(_PositionToken):
-    """Token to advance to a specific column of input text; useful for tabular report scraping."""
-    def __init__( self, colno ):
-        super(GoToColumn,self).__init__()
-        self.col = colno
-
-    def preParse( self, instring, loc ):
-        if col(loc,instring) != self.col:
-            instrlen = len(instring)
-            if self.ignoreExprs:
-                loc = self._skipIgnorables( instring, loc )
-            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
-                loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        thiscol = col( loc, instring )
-        if thiscol > self.col:
-            raise ParseException( instring, loc, "Text not in expected column", self )
-        newloc = loc + self.col - thiscol
-        ret = instring[ loc: newloc ]
-        return newloc, ret
-
-class LineStart(_PositionToken):
-    """Matches if current position is at the beginning of a line within the parse string"""
-    def __init__( self ):
-        super(LineStart,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected start of line"
-
-    def preParse( self, instring, loc ):
-        preloc = super(LineStart,self).preParse(instring,loc)
-        if instring[preloc] == "\n":
-            loc += 1
-        return loc
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if not( loc==0 or
-            (loc == self.preParse( instring, 0 )) or
-            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
-            raise ParseException(instring, loc, self.errmsg, self)
-        return loc, []
-
-class LineEnd(_PositionToken):
-    """Matches if current position is at the end of a line within the parse string"""
-    def __init__( self ):
-        super(LineEnd,self).__init__()
-        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
-        self.errmsg = "Expected end of line"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc<len(instring):
-            if instring[loc] == "\n":
-                return loc+1, "\n"
-            else:
-                raise ParseException(instring, loc, self.errmsg, self)
-        elif loc == len(instring):
-            return loc+1, []
-        else:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-class StringStart(_PositionToken):
-    """Matches if current position is at the beginning of the parse string"""
-    def __init__( self ):
-        super(StringStart,self).__init__()
-        self.errmsg = "Expected start of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc != 0:
-            # see if entire string up to here is just whitespace and ignoreables
-            if loc != self.preParse( instring, 0 ):
-                raise ParseException(instring, loc, self.errmsg, self)
-        return loc, []
-
-class StringEnd(_PositionToken):
-    """Matches if current position is at the end of the parse string"""
-    def __init__( self ):
-        super(StringEnd,self).__init__()
-        self.errmsg = "Expected end of text"
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if loc < len(instring):
-            raise ParseException(instring, loc, self.errmsg, self)
-        elif loc == len(instring):
-            return loc+1, []
-        elif loc > len(instring):
-            return loc, []
-        else:
-            raise ParseException(instring, loc, self.errmsg, self)
-
-class WordStart(_PositionToken):
-    """Matches if the current position is at the beginning of a Word, and
-       is not preceded by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of
-       the string being parsed, or at the beginning of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordStart,self).__init__()
-        self.wordChars = set(wordChars)
-        self.errmsg = "Not at the start of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        if loc != 0:
-            if (instring[loc-1] in self.wordChars or
-                instring[loc] not in self.wordChars):
-                raise ParseException(instring, loc, self.errmsg, self)
-        return loc, []
-
-class WordEnd(_PositionToken):
-    """Matches if the current position is at the end of a Word, and
-       is not followed by any character in a given set of C{wordChars}
-       (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
-       use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of
-       the string being parsed, or at the end of a line.
-    """
-    def __init__(self, wordChars = printables):
-        super(WordEnd,self).__init__()
-        self.wordChars = set(wordChars)
-        self.skipWhitespace = False
-        self.errmsg = "Not at the end of a word"
-
-    def parseImpl(self, instring, loc, doActions=True ):
-        instrlen = len(instring)
-        if instrlen>0 and loc<instrlen:
-            if (instring[loc] in self.wordChars or
-                instring[loc-1] not in self.wordChars):
-                raise ParseException(instring, loc, self.errmsg, self)
-        return loc, []
-
-
-class ParseExpression(ParserElement):
-    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
-    def __init__( self, exprs, savelist = False ):
-        super(ParseExpression,self).__init__(savelist)
-        if isinstance( exprs, list ):
-            self.exprs = exprs
-        elif isinstance( exprs, basestring ):
-            self.exprs = [ Literal( exprs ) ]
-        else:
-            try:
-                self.exprs = list( exprs )
-            except TypeError:
-                self.exprs = [ exprs ]
-        self.callPreparse = False
-
-    def __getitem__( self, i ):
-        return self.exprs[i]
-
-    def append( self, other ):
-        self.exprs.append( other )
-        self.strRepr = None
-        return self
-
-    def leaveWhitespace( self ):
-        """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on
-           all contained expressions."""
-        self.skipWhitespace = False
-        self.exprs = [ e.copy() for e in self.exprs ]
-        for e in self.exprs:
-            e.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseExpression, self).ignore( other )
-                for e in self.exprs:
-                    e.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseExpression, self).ignore( other )
-            for e in self.exprs:
-                e.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def __str__( self ):
-        try:
-            return super(ParseExpression,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
-        return self.strRepr
-
-    def streamline( self ):
-        super(ParseExpression,self).streamline()
-
-        for e in self.exprs:
-            e.streamline()
-
-        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
-        # but only if there are no parse actions or resultsNames on the nested And's
-        # (likewise for Or's and MatchFirst's)
-        if ( len(self.exprs) == 2 ):
-            other = self.exprs[0]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = other.exprs[:] + [ self.exprs[1] ]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-            other = self.exprs[-1]
-            if ( isinstance( other, self.__class__ ) and
-                  not(other.parseAction) and
-                  other.resultsName is None and
-                  not other.debug ):
-                self.exprs = self.exprs[:-1] + other.exprs[:]
-                self.strRepr = None
-                self.mayReturnEmpty |= other.mayReturnEmpty
-                self.mayIndexError  |= other.mayIndexError
-
-        return self
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
-        return ret
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        for e in self.exprs:
-            e.validate(tmp)
-        self.checkRecursion( [] )
-        
-    def copy(self):
-        ret = super(ParseExpression,self).copy()
-        ret.exprs = [e.copy() for e in self.exprs]
-        return ret
-
-class And(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found in the given order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'+'} operator.
-    """
-
-    class _ErrorStop(Empty):
-        def __init__(self, *args, **kwargs):
-            super(And._ErrorStop,self).__init__(*args, **kwargs)
-            self.leaveWhitespace()
-
-    def __init__( self, exprs, savelist = True ):
-        super(And,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.setWhitespaceChars( exprs[0].whiteChars )
-        self.skipWhitespace = exprs[0].skipWhitespace
-        self.callPreparse = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        # pass False as last arg to _parse for first element, since we already
-        # pre-parsed the string as part of our And pre-parsing
-        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
-        errorStop = False
-        for e in self.exprs[1:]:
-            if isinstance(e, And._ErrorStop):
-                errorStop = True
-                continue
-            if errorStop:
-                try:
-                    loc, exprtokens = e._parse( instring, loc, doActions )
-                except ParseSyntaxException:
-                    raise
-                except ParseBaseException as pe:
-                    pe.__traceback__ = None
-                    raise ParseSyntaxException(pe)
-                except IndexError:
-                    raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
-            else:
-                loc, exprtokens = e._parse( instring, loc, doActions )
-            if exprtokens or exprtokens.keys():
-                resultlist += exprtokens
-        return loc, resultlist
-
-    def __iadd__(self, other ):
-        if isinstance( other, basestring ):
-            other = Literal( other )
-        return self.append( other ) #And( [ self, other ] )
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-            if not e.mayReturnEmpty:
-                break
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-
-class Or(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the expression that matches the longest string will be used.
-       May be constructed using the C{'^'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(Or,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = False
-        for e in self.exprs:
-            if e.mayReturnEmpty:
-                self.mayReturnEmpty = True
-                break
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxMatchLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                loc2 = e.tryParse( instring, loc )
-            except ParseException as err:
-                err.__traceback__ = None
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-            else:
-                if loc2 > maxMatchLoc:
-                    maxMatchLoc = loc2
-                    maxMatchExp = e
-
-        if maxMatchLoc < 0:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-        return maxMatchExp._parse( instring, loc, doActions )
-
-    def __ixor__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #Or( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class MatchFirst(ParseExpression):
-    """Requires that at least one C{ParseExpression} is found.
-       If two expressions match, the first one listed is the one that will match.
-       May be constructed using the C{'|'} operator.
-    """
-    def __init__( self, exprs, savelist = False ):
-        super(MatchFirst,self).__init__(exprs, savelist)
-        if exprs:
-            self.mayReturnEmpty = False
-            for e in self.exprs:
-                if e.mayReturnEmpty:
-                    self.mayReturnEmpty = True
-                    break
-        else:
-            self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        maxExcLoc = -1
-        maxException = None
-        for e in self.exprs:
-            try:
-                ret = e._parse( instring, loc, doActions )
-                return ret
-            except ParseException as err:
-                if err.loc > maxExcLoc:
-                    maxException = err
-                    maxExcLoc = err.loc
-            except IndexError:
-                if len(instring) > maxExcLoc:
-                    maxException = ParseException(instring,len(instring),e.errmsg,self)
-                    maxExcLoc = len(instring)
-
-        # only got here if no expression matched, raise exception for match that made it the furthest
-        else:
-            if maxException is not None:
-                raise maxException
-            else:
-                raise ParseException(instring, loc, "no defined alternatives to match", self)
-
-    def __ior__(self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass( other )
-        return self.append( other ) #MatchFirst( [ self, other ] )
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class Each(ParseExpression):
-    """Requires all given C{ParseExpression}s to be found, but in any order.
-       Expressions may be separated by whitespace.
-       May be constructed using the C{'&'} operator.
-    """
-    def __init__( self, exprs, savelist = True ):
-        super(Each,self).__init__(exprs, savelist)
-        self.mayReturnEmpty = True
-        for e in self.exprs:
-            if not e.mayReturnEmpty:
-                self.mayReturnEmpty = False
-                break
-        self.skipWhitespace = True
-        self.initExprGroups = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.initExprGroups:
-            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
-            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ]
-            self.optionals = opt1 + opt2
-            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
-            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
-            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
-            self.required += self.multirequired
-            self.initExprGroups = False
-        tmpLoc = loc
-        tmpReqd = self.required[:]
-        tmpOpt  = self.optionals[:]
-        matchOrder = []
-
-        keepMatching = True
-        while keepMatching:
-            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
-            failed = []
-            for e in tmpExprs:
-                try:
-                    tmpLoc = e.tryParse( instring, tmpLoc )
-                except ParseException:
-                    failed.append(e)
-                else:
-                    matchOrder.append(e)
-                    if e in tmpReqd:
-                        tmpReqd.remove(e)
-                    elif e in tmpOpt:
-                        tmpOpt.remove(e)
-            if len(failed) == len(tmpExprs):
-                keepMatching = False
-
-        if tmpReqd:
-            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
-            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
-
-        # add any unmatched Optionals, in case they have default values defined
-        matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt)
-
-        resultlist = []
-        for e in matchOrder:
-            loc,results = e._parse(instring,loc,doActions)
-            resultlist.append(results)
-
-        finalResults = ParseResults([])
-        for r in resultlist:
-            dups = {}
-            for k in r.keys():
-                if k in finalResults.keys():
-                    tmp = ParseResults(finalResults[k])
-                    tmp += ParseResults(r[k])
-                    dups[k] = tmp
-            finalResults += ParseResults(r)
-            for k,v in dups.items():
-                finalResults[k] = v
-        return loc, finalResults
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
-
-        return self.strRepr
-
-    def checkRecursion( self, parseElementList ):
-        subRecCheckList = parseElementList[:] + [ self ]
-        for e in self.exprs:
-            e.checkRecursion( subRecCheckList )
-
-
-class ParseElementEnhance(ParserElement):
-    """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens."""
-    def __init__( self, expr, savelist=False ):
-        super(ParseElementEnhance,self).__init__(savelist)
-        if isinstance( expr, basestring ):
-            expr = Literal(expr)
-        self.expr = expr
-        self.strRepr = None
-        if expr is not None:
-            self.mayIndexError = expr.mayIndexError
-            self.mayReturnEmpty = expr.mayReturnEmpty
-            self.setWhitespaceChars( expr.whiteChars )
-            self.skipWhitespace = expr.skipWhitespace
-            self.saveAsList = expr.saveAsList
-            self.callPreparse = expr.callPreparse
-            self.ignoreExprs.extend(expr.ignoreExprs)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        if self.expr is not None:
-            return self.expr._parse( instring, loc, doActions, callPreParse=False )
-        else:
-            raise ParseException("",loc,self.errmsg,self)
-
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        self.expr = self.expr.copy()
-        if self.expr is not None:
-            self.expr.leaveWhitespace()
-        return self
-
-    def ignore( self, other ):
-        if isinstance( other, Suppress ):
-            if other not in self.ignoreExprs:
-                super( ParseElementEnhance, self).ignore( other )
-                if self.expr is not None:
-                    self.expr.ignore( self.ignoreExprs[-1] )
-        else:
-            super( ParseElementEnhance, self).ignore( other )
-            if self.expr is not None:
-                self.expr.ignore( self.ignoreExprs[-1] )
-        return self
-
-    def streamline( self ):
-        super(ParseElementEnhance,self).streamline()
-        if self.expr is not None:
-            self.expr.streamline()
-        return self
-
-    def checkRecursion( self, parseElementList ):
-        if self in parseElementList:
-            raise RecursiveGrammarException( parseElementList+[self] )
-        subRecCheckList = parseElementList[:] + [ self ]
-        if self.expr is not None:
-            self.expr.checkRecursion( subRecCheckList )
-
-    def validate( self, validateTrace=[] ):
-        tmp = validateTrace[:]+[self]
-        if self.expr is not None:
-            self.expr.validate(tmp)
-        self.checkRecursion( [] )
-
-    def __str__( self ):
-        try:
-            return super(ParseElementEnhance,self).__str__()
-        except:
-            pass
-
-        if self.strRepr is None and self.expr is not None:
-            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
-        return self.strRepr
-
-
-class FollowedBy(ParseElementEnhance):
-    """Lookahead matching of the given parse expression.  C{FollowedBy}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression matches at the current
-    position.  C{FollowedBy} always returns a null token list."""
-    def __init__( self, expr ):
-        super(FollowedBy,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        self.expr.tryParse( instring, loc )
-        return loc, []
-
-
-class NotAny(ParseElementEnhance):
-    """Lookahead to disallow matching with the given parse expression.  C{NotAny}
-    does *not* advance the parsing position within the input string, it only
-    verifies that the specified parse expression does *not* match at the current
-    position.  Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny}
-    always returns a null token list.  May be constructed using the '~' operator."""
-    def __init__( self, expr ):
-        super(NotAny,self).__init__(expr)
-        #~ self.leaveWhitespace()
-        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
-        self.mayReturnEmpty = True
-        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            self.expr.tryParse( instring, loc )
-        except (ParseException,IndexError):
-            pass
-        else:
-            raise ParseException(instring, loc, self.errmsg, self)
-        return loc, []
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "~{" + _ustr(self.expr) + "}"
-
-        return self.strRepr
-
-
-class ZeroOrMore(ParseElementEnhance):
-    """Optional repetition of zero or more of the given expression."""
-    def __init__( self, expr ):
-        super(ZeroOrMore,self).__init__(expr)
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        tokens = []
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-
-class OneOrMore(ParseElementEnhance):
-    """Repetition of one or more of the given expression."""
-    def parseImpl( self, instring, loc, doActions=True ):
-        # must be at least one
-        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        try:
-            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
-            while 1:
-                if hasIgnoreExprs:
-                    preloc = self._skipIgnorables( instring, loc )
-                else:
-                    preloc = loc
-                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
-                if tmptokens or tmptokens.keys():
-                    tokens += tmptokens
-        except (ParseException,IndexError):
-            pass
-
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "{" + _ustr(self.expr) + "}..."
-
-        return self.strRepr
-
-    def setResultsName( self, name, listAllMatches=False ):
-        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
-        ret.saveAsList = True
-        return ret
-
-class _NullToken(object):
-    def __bool__(self):
-        return False
-    __nonzero__ = __bool__
-    def __str__(self):
-        return ""
-
-_optionalNotMatched = _NullToken()
-class Optional(ParseElementEnhance):
-    """Optional matching of the given expression.
-       A default return string can also be specified, if the optional expression
-       is not found.
-    """
-    def __init__( self, exprs, default=_optionalNotMatched ):
-        super(Optional,self).__init__( exprs, savelist=False )
-        self.defaultValue = default
-        self.mayReturnEmpty = True
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        try:
-            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
-        except (ParseException,IndexError):
-            if self.defaultValue is not _optionalNotMatched:
-                if self.expr.resultsName:
-                    tokens = ParseResults([ self.defaultValue ])
-                    tokens[self.expr.resultsName] = self.defaultValue
-                else:
-                    tokens = [ self.defaultValue ]
-            else:
-                tokens = []
-        return loc, tokens
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        if self.strRepr is None:
-            self.strRepr = "[" + _ustr(self.expr) + "]"
-
-        return self.strRepr
-
-
-class SkipTo(ParseElementEnhance):
-    """Token for skipping over all undefined text until the matched expression is found.
-       If C{include} is set to true, the matched expression is also parsed (the skipped text
-       and matched expression are returned as a 2-element list).  The C{ignore}
-       argument is used to define grammars (typically quoted strings and comments) that
-       might contain false matches.
-    """
-    def __init__( self, other, include=False, ignore=None, failOn=None ):
-        super( SkipTo, self ).__init__( other )
-        self.ignoreExpr = ignore
-        self.mayReturnEmpty = True
-        self.mayIndexError = False
-        self.includeMatch = include
-        self.asList = False
-        if failOn is not None and isinstance(failOn, basestring):
-            self.failOn = Literal(failOn)
-        else:
-            self.failOn = failOn
-        self.errmsg = "No match found for "+_ustr(self.expr)
-
-    def parseImpl( self, instring, loc, doActions=True ):
-        startLoc = loc
-        instrlen = len(instring)
-        expr = self.expr
-        failParse = False
-        while loc <= instrlen:
-            try:
-                if self.failOn:
-                    try:
-                        self.failOn.tryParse(instring, loc)
-                    except ParseBaseException:
-                        pass
-                    else:
-                        failParse = True
-                        raise ParseException(instring, loc, "Found expression " + str(self.failOn))
-                    failParse = False
-                if self.ignoreExpr is not None:
-                    while 1:
-                        try:
-                            loc = self.ignoreExpr.tryParse(instring,loc)
-                            # print("found ignoreExpr, advance to", loc)
-                        except ParseBaseException:
-                            break
-                expr._parse( instring, loc, doActions=False, callPreParse=False )
-                skipText = instring[startLoc:loc]
-                if self.includeMatch:
-                    loc,mat = expr._parse(instring,loc,doActions,callPreParse=False)
-                    if mat:
-                        skipRes = ParseResults( skipText )
-                        skipRes += mat
-                        return loc, [ skipRes ]
-                    else:
-                        return loc, [ skipText ]
-                else:
-                    return loc, [ skipText ]
-            except (ParseException,IndexError):
-                if failParse:
-                    raise
-                else:
-                    loc += 1
-        raise ParseException(instring, loc, self.errmsg, self)
-
-class Forward(ParseElementEnhance):
-    """Forward declaration of an expression to be defined later -
-       used for recursive grammars, such as algebraic infix notation.
-       When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.
-
-       Note: take care when assigning to C{Forward} not to overlook precedence of operators.
-       Specifically, '|' has a lower precedence than '<<', so that::
-          fwdExpr << a | b | c
-       will actually be evaluated as::
-          (fwdExpr << a) | b | c
-       thereby leaving b and c out as parseable alternatives.  It is recommended that you
-       explicitly group the values inserted into the C{Forward}::
-          fwdExpr << (a | b | c)
-       Converting to use the '<<=' operator instead will avoid this problem.
-    """
-    def __init__( self, other=None ):
-        super(Forward,self).__init__( other, savelist=False )
-
-    def __lshift__( self, other ):
-        if isinstance( other, basestring ):
-            other = ParserElement.literalStringClass(other)
-        self.expr = other
-        self.mayReturnEmpty = other.mayReturnEmpty
-        self.strRepr = None
-        self.mayIndexError = self.expr.mayIndexError
-        self.mayReturnEmpty = self.expr.mayReturnEmpty
-        self.setWhitespaceChars( self.expr.whiteChars )
-        self.skipWhitespace = self.expr.skipWhitespace
-        self.saveAsList = self.expr.saveAsList
-        self.ignoreExprs.extend(self.expr.ignoreExprs)
-        return None
-    __ilshift__ = __lshift__
-    
-    def leaveWhitespace( self ):
-        self.skipWhitespace = False
-        return self
-
-    def streamline( self ):
-        if not self.streamlined:
-            self.streamlined = True
-            if self.expr is not None:
-                self.expr.streamline()
-        return self
-
-    def validate( self, validateTrace=[] ):
-        if self not in validateTrace:
-            tmp = validateTrace[:]+[self]
-            if self.expr is not None:
-                self.expr.validate(tmp)
-        self.checkRecursion([])
-
-    def __str__( self ):
-        if hasattr(self,"name"):
-            return self.name
-
-        self._revertClass = self.__class__
-        self.__class__ = _ForwardNoRecurse
-        try:
-            if self.expr is not None:
-                retString = _ustr(self.expr)
-            else:
-                retString = "None"
-        finally:
-            self.__class__ = self._revertClass
-        return self.__class__.__name__ + ": " + retString
-
-    def copy(self):
-        if self.expr is not None:
-            return super(Forward,self).copy()
-        else:
-            ret = Forward()
-            ret << self
-            return ret
-
-class _ForwardNoRecurse(Forward):
-    def __str__( self ):
-        return "..."
-
-class TokenConverter(ParseElementEnhance):
-    """Abstract subclass of C{ParseExpression}, for converting parsed results."""
-    def __init__( self, expr, savelist=False ):
-        super(TokenConverter,self).__init__( expr )#, savelist )
-        self.saveAsList = False
-
-class Upcase(TokenConverter):
-    """Converter to upper case all matching tokens."""
-    def __init__(self, *args):
-        super(Upcase,self).__init__(*args)
-        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead",
-                       DeprecationWarning,stacklevel=2)
-
-    def postParse( self, instring, loc, tokenlist ):
-        return list(map( str.upper, tokenlist ))
-
-
-class Combine(TokenConverter):
-    """Converter to concatenate all matching tokens to a single string.
-       By default, the matching patterns must also be contiguous in the input string;
-       this can be disabled by specifying C{'adjacent=False'} in the constructor.
-    """
-    def __init__( self, expr, joinString="", adjacent=True ):
-        super(Combine,self).__init__( expr )
-        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
-        if adjacent:
-            self.leaveWhitespace()
-        self.adjacent = adjacent
-        self.skipWhitespace = True
-        self.joinString = joinString
-        self.callPreparse = True
-
-    def ignore( self, other ):
-        if self.adjacent:
-            ParserElement.ignore(self, other)
-        else:
-            super( Combine, self).ignore( other )
-        return self
-
-    def postParse( self, instring, loc, tokenlist ):
-        retToks = tokenlist.copy()
-        del retToks[:]
-        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
-
-        if self.resultsName and len(retToks.keys())>0:
-            return [ retToks ]
-        else:
-            return retToks
-
-class Group(TokenConverter):
-    """Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions."""
-    def __init__( self, expr ):
-        super(Group,self).__init__( expr )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        return [ tokenlist ]
-
-class Dict(TokenConverter):
-    """Converter to return a repetitive expression as a list, but also as a dictionary.
-       Each element can also be referenced using the first token in the expression as its key.
-       Useful for tabular report scraping when the first column can be used as a item key.
-    """
-    def __init__( self, exprs ):
-        super(Dict,self).__init__( exprs )
-        self.saveAsList = True
-
-    def postParse( self, instring, loc, tokenlist ):
-        for i,tok in enumerate(tokenlist):
-            if len(tok) == 0:
-                continue
-            ikey = tok[0]
-            if isinstance(ikey,int):
-                ikey = _ustr(tok[0]).strip()
-            if len(tok)==1:
-                tokenlist[ikey] = _ParseResultsWithOffset("",i)
-            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
-                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
-            else:
-                dictvalue = tok.copy() #ParseResults(i)
-                del dictvalue[0]
-                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
-                else:
-                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
-
-        if self.resultsName:
-            return [ tokenlist ]
-        else:
-            return tokenlist
-
-
-class Suppress(TokenConverter):
-    """Converter for ignoring the results of a parsed expression."""
-    def postParse( self, instring, loc, tokenlist ):
-        return []
-
-    def suppress( self ):
-        return self
-
-
-class OnlyOnce(object):
-    """Wrapper for parse actions, to ensure they are only called once."""
-    def __init__(self, methodCall):
-        self.callable = _trim_arity(methodCall)
-        self.called = False
-    def __call__(self,s,l,t):
-        if not self.called:
-            results = self.callable(s,l,t)
-            self.called = True
-            return results
-        raise ParseException(s,l,"")
-    def reset(self):
-        self.called = False
-
-def traceParseAction(f):
-    """Decorator for debugging parse actions."""
-    f = _trim_arity(f)
-    def z(*paArgs):
-        thisFunc = f.func_name
-        s,l,t = paArgs[-3:]
-        if len(paArgs)>3:
-            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
-        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
-        try:
-            ret = f(*paArgs)
-        except Exception as exc:
-            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
-            raise
-        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
-        return ret
-    try:
-        z.__name__ = f.__name__
-    except AttributeError:
-        pass
-    return z
-
-#
-# global helpers
-#
-def delimitedList( expr, delim=",", combine=False ):
-    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
-       By default, the list elements and delimiters can have intervening whitespace, and
-       comments, but this can be overridden by passing C{combine=True} in the constructor.
-       If C{combine} is set to C{True}, the matching tokens are returned as a single token
-       string, with the delimiters included; otherwise, the matching tokens are returned
-       as a list of tokens, with the delimiters suppressed.
-    """
-    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
-    if combine:
-        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
-    else:
-        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
-
-def countedArray( expr, intExpr=None ):
-    """Helper to define a counted list of expressions.
-       This helper defines a pattern of the form::
-           integer expr expr expr...
-       where the leading integer tells how many expr expressions follow.
-       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
-    """
-    arrayExpr = Forward()
-    def countFieldParseAction(s,l,t):
-        n = t[0]
-        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
-        return []
-    if intExpr is None:
-        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
-    else:
-        intExpr = intExpr.copy()
-    intExpr.setName("arrayLen")
-    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
-    return ( intExpr + arrayExpr )
-
-def _flatten(L):
-    ret = []
-    for i in L:
-        if isinstance(i,list):
-            ret.extend(_flatten(i))
-        else:
-            ret.append(i)
-    return ret
-
-def matchPreviousLiteral(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousLiteral(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches a
-       previous literal, will also match the leading C{"1:1"} in C{"1:10"}.
-       If this is not desired, use C{matchPreviousExpr}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    def copyTokenToRepeater(s,l,t):
-        if t:
-            if len(t) == 1:
-                rep << t[0]
-            else:
-                # flatten t tokens
-                tflat = _flatten(t.asList())
-                rep << And( [ Literal(tt) for tt in tflat ] )
-        else:
-            rep << Empty()
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def matchPreviousExpr(expr):
-    """Helper to define an expression that is indirectly defined from
-       the tokens matched in a previous expression, that is, it looks
-       for a 'repeat' of a previous expression.  For example::
-           first = Word(nums)
-           second = matchPreviousExpr(first)
-           matchExpr = first + ":" + second
-       will match C{"1:1"}, but not C{"1:2"}.  Because this matches by
-       expressions, will *not* match the leading C{"1:1"} in C{"1:10"};
-       the expressions are evaluated first, and then compared, so
-       C{"1"} is compared with C{"10"}.
-       Do *not* use with packrat parsing enabled.
-    """
-    rep = Forward()
-    e2 = expr.copy()
-    rep << e2
-    def copyTokenToRepeater(s,l,t):
-        matchTokens = _flatten(t.asList())
-        def mustMatchTheseTokens(s,l,t):
-            theseTokens = _flatten(t.asList())
-            if  theseTokens != matchTokens:
-                raise ParseException("",0,"")
-        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
-    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
-    return rep
-
-def _escapeRegexRangeChars(s):
-    #~  escape these chars: ^-]
-    for c in r"\^-]":
-        s = s.replace(c,_bslash+c)
-    s = s.replace("\n",r"\n")
-    s = s.replace("\t",r"\t")
-    return _ustr(s)
-
-def oneOf( strs, caseless=False, useRegex=True ):
-    """Helper to quickly define a set of alternative Literals, and makes sure to do
-       longest-first testing when there is a conflict, regardless of the input order,
-       but returns a C{L{MatchFirst}} for best performance.
-
-       Parameters:
-        - strs - a string of space-delimited literals, or a list of string literals
-        - caseless - (default=False) - treat all literals as caseless
-        - useRegex - (default=True) - as an optimization, will generate a Regex
-          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or
-          if creating a C{Regex} raises an exception)
-    """
-    if caseless:
-        isequal = ( lambda a,b: a.upper() == b.upper() )
-        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
-        parseElementClass = CaselessLiteral
-    else:
-        isequal = ( lambda a,b: a == b )
-        masks = ( lambda a,b: b.startswith(a) )
-        parseElementClass = Literal
-
-    if isinstance(strs,(list,tuple)):
-        symbols = list(strs[:])
-    elif isinstance(strs,basestring):
-        symbols = strs.split()
-    else:
-        warnings.warn("Invalid argument to oneOf, expected string or list",
-                SyntaxWarning, stacklevel=2)
-
-    i = 0
-    while i < len(symbols)-1:
-        cur = symbols[i]
-        for j,other in enumerate(symbols[i+1:]):
-            if ( isequal(other, cur) ):
-                del symbols[i+j+1]
-                break
-            elif ( masks(cur, other) ):
-                del symbols[i+j+1]
-                symbols.insert(i,other)
-                cur = other
-                break
-        else:
-            i += 1
-
-    if not caseless and useRegex:
-        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
-        try:
-            if len(symbols)==len("".join(symbols)):
-                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
-            else:
-                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
-        except:
-            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
-                    SyntaxWarning, stacklevel=2)
-
-
-    # last resort, just use MatchFirst
-    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
-
-def dictOf( key, value ):
-    """Helper to easily and clearly define a dictionary by specifying the respective patterns
-       for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens
-       in the proper order.  The key pattern can include delimiting markers or punctuation,
-       as long as they are suppressed, thereby leaving the significant key text.  The value
-       pattern can include named results, so that the C{Dict} results can include named token
-       fields.
-    """
-    return Dict( ZeroOrMore( Group ( key + value ) ) )
-
-def originalTextFor(expr, asString=True):
-    """Helper to return the original, untokenized text for a given expression.  Useful to
-       restore the parsed fields of an HTML start tag into the raw tag text itself, or to
-       revert separate tokens with intervening whitespace back to the original matching
-       input text. Simpler to use than the parse action C{L{keepOriginalText}}, and does not
-       require the inspect module to chase up the call stack.  By default, returns a 
-       string containing the original parsed text.  
-       
-       If the optional C{asString} argument is passed as C{False}, then the return value is a 
-       C{L{ParseResults}} containing any results names that were originally matched, and a 
-       single token containing the original matched text from the input string.  So if 
-       the expression passed to C{L{originalTextFor}} contains expressions with defined
-       results names, you must set C{asString} to C{False} if you want to preserve those
-       results name values."""
-    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
-    endlocMarker = locMarker.copy()
-    endlocMarker.callPreparse = False
-    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
-    if asString:
-        extractText = lambda s,l,t: s[t._original_start:t._original_end]
-    else:
-        def extractText(s,l,t):
-            del t[:]
-            t.insert(0, s[t._original_start:t._original_end])
-            del t["_original_start"]
-            del t["_original_end"]
-    matchExpr.setParseAction(extractText)
-    return matchExpr
-
-def ungroup(expr): 
-    """Helper to undo pyparsing's default grouping of And expressions, even
-       if all but one are non-empty."""
-    return TokenConverter(expr).setParseAction(lambda t:t[0])
-
-# convenience constants for positional expressions
-empty       = Empty().setName("empty")
-lineStart   = LineStart().setName("lineStart")
-lineEnd     = LineEnd().setName("lineEnd")
-stringStart = StringStart().setName("stringStart")
-stringEnd   = StringEnd().setName("stringEnd")
-
-_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
-_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
-_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
-_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
-_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
-_charRange = Group(_singleChar + Suppress("-") + _singleChar)
-_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
-
-_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
-
-def srange(s):
-    r"""Helper to easily define string ranges for use in Word construction.  Borrows
-       syntax from regexp '[]' string range definitions::
-          srange("[0-9]")   -> "0123456789"
-          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
-          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
-       The input string must be enclosed in []'s, and the returned string is the expanded
-       character set joined into a single string.
-       The values enclosed in the []'s may be::
-          a single character
-          an escaped character with a leading backslash (such as \- or \])
-          an escaped hex character with a leading '\x' (\x21, which is a '!' character) 
-            (\0x## is also supported for backwards compatibility) 
-          an escaped octal character with a leading '\0' (\041, which is a '!' character)
-          a range of any of the above, separated by a dash ('a-z', etc.)
-          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
-    """
-    try:
-        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
-    except:
-        return ""
-
-def matchOnlyAtCol(n):
-    """Helper method for defining parse actions that require matching at a specific
-       column in the input text.
-    """
-    def verifyCol(strg,locn,toks):
-        if col(locn,strg) != n:
-            raise ParseException(strg,locn,"matched token not at column %d" % n)
-    return verifyCol
-
-def replaceWith(replStr):
-    """Helper method for common parse actions that simply return a literal value.  Especially
-       useful when used with C{L{transformString<ParserElement.transformString>}()}.
-    """
-    def _replFunc(*args):
-        return [replStr]
-    return _replFunc
-
-def removeQuotes(s,l,t):
-    """Helper parse action for removing quotation marks from parsed quoted strings.
-       To use, add this parse action to quoted string using::
-         quotedString.setParseAction( removeQuotes )
-    """
-    return t[0][1:-1]
-
-def upcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to upper case."""
-    return [ tt.upper() for tt in map(_ustr,t) ]
-
-def downcaseTokens(s,l,t):
-    """Helper parse action to convert tokens to lower case."""
-    return [ tt.lower() for tt in map(_ustr,t) ]
-
-def keepOriginalText(s,startLoc,t):
-    """DEPRECATED - use new helper method C{L{originalTextFor}}.
-       Helper parse action to preserve original parsed text,
-       overriding any nested parse actions."""
-    try:
-        endloc = getTokensEndLoc()
-    except ParseException:
-        raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
-    del t[:]
-    t += ParseResults(s[startLoc:endloc])
-    return t
-
-def getTokensEndLoc():
-    """Method to be called from within a parse action to determine the end
-       location of the parsed tokens."""
-    import inspect
-    fstack = inspect.stack()
-    try:
-        # search up the stack (through intervening argument normalizers) for correct calling routine
-        for f in fstack[2:]:
-            if f[3] == "_parseNoCache":
-                endloc = f[0].f_locals["loc"]
-                return endloc
-        else:
-            raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
-    finally:
-        del fstack
-
-def _makeTags(tagStr, xml):
-    """Internal helper to construct opening and closing tag expressions, given a tag name"""
-    if isinstance(tagStr,basestring):
-        resname = tagStr
-        tagStr = Keyword(tagStr, caseless=not xml)
-    else:
-        resname = tagStr.name
-
-    tagAttrName = Word(alphas,alphanums+"_-:")
-    if (xml):
-        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    else:
-        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
-        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
-        openTag = Suppress("<") + tagStr("tag") + \
-                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
-                Optional( Suppress("=") + tagAttrValue ) ))) + \
-                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
-    closeTag = Combine(_L("</") + tagStr + ">")
-
-    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
-    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
-    openTag.tag = resname
-    closeTag.tag = resname
-    return openTag, closeTag
-
-def makeHTMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
-    return _makeTags( tagStr, False )
-
-def makeXMLTags(tagStr):
-    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
-    return _makeTags( tagStr, True )
-
-def withAttribute(*args,**attrDict):
-    """Helper to create a validating parse action to be used with start tags created
-       with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag
-       with a required attribute value, to avoid false matches on common tags such as
-       C{<TD>} or C{<DIV>}.
-
-       Call C{withAttribute} with a series of attribute names and values. Specify the list
-       of filter attributes names and values as:
-        - keyword arguments, as in C{(align="right")}, or
-        - as an explicit dict with C{**} operator, when an attribute name is also a Python
-          reserved word, as in C{**{"class":"Customer", "align":"right"}}
-        - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
-       For attribute names with a namespace prefix, you must use the second form.  Attribute
-       names are matched insensitive to upper/lower case.
-
-       To verify that the attribute exists, but without specifying a value, pass
-       C{withAttribute.ANY_VALUE} as the value.
-       """
-    if args:
-        attrs = args[:]
-    else:
-        attrs = attrDict.items()
-    attrs = [(k,v) for k,v in attrs]
-    def pa(s,l,tokens):
-        for attrName,attrValue in attrs:
-            if attrName not in tokens:
-                raise ParseException(s,l,"no matching attribute " + attrName)
-            if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
-                raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
-                                            (attrName, tokens[attrName], attrValue))
-    return pa
-withAttribute.ANY_VALUE = object()
-
-opAssoc = _Constants()
-opAssoc.LEFT = object()
-opAssoc.RIGHT = object()
-
-def operatorPrecedence( baseExpr, opList ):
-    """Helper method for constructing grammars of expressions made up of
-       operators working in a precedence hierarchy.  Operators may be unary or
-       binary, left- or right-associative.  Parse actions can also be attached
-       to operator expressions.
-
-       Parameters:
-        - baseExpr - expression representing the most basic element for the nested
-        - opList - list of tuples, one for each operator precedence level in the
-          expression grammar; each tuple is of the form
-          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
-           - opExpr is the pyparsing expression for the operator;
-              may also be a string, which will be converted to a Literal;
-              if numTerms is 3, opExpr is a tuple of two expressions, for the
-              two operators separating the 3 terms
-           - numTerms is the number of terms for this operator (must
-              be 1, 2, or 3)
-           - rightLeftAssoc is the indicator whether the operator is
-              right or left associative, using the pyparsing-defined
-              constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}.
-           - parseAction is the parse action to be associated with
-              expressions matching this operator expression (the
-              parse action tuple member may be omitted)
-    """
-    ret = Forward()
-    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
-    for i,operDef in enumerate(opList):
-        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
-        if arity == 3:
-            if opExpr is None or len(opExpr) != 2:
-                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
-            opExpr1, opExpr2 = opExpr
-        thisExpr = Forward()#.setName("expr%d" % i)
-        if rightLeftAssoc == opAssoc.LEFT:
-            if arity == 1:
-                matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
-                            Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        elif rightLeftAssoc == opAssoc.RIGHT:
-            if arity == 1:
-                # try to avoid LR with this extra test
-                if not isinstance(opExpr, Optional):
-                    opExpr = Optional(opExpr)
-                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
-            elif arity == 2:
-                if opExpr is not None:
-                    matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
-                else:
-                    matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
-            elif arity == 3:
-                matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
-                            Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
-            else:
-                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
-        else:
-            raise ValueError("operator must indicate right or left associativity")
-        if pa:
-            matchExpr.setParseAction( pa )
-        thisExpr << ( matchExpr | lastExpr )
-        lastExpr = thisExpr
-    ret << lastExpr
-    return ret
-
-dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
-sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
-quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
-unicodeString = Combine(_L('u') + quotedString.copy())
-
-def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()):
-    """Helper method for defining nested lists enclosed in opening and closing
-       delimiters ("(" and ")" are the default).
-
-       Parameters:
-        - opener - opening character for a nested list (default="("); can also be a pyparsing expression
-        - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
-        - content - expression for items within the nested lists (default=None)
-        - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
-
-       If an expression is not provided for the content argument, the nested
-       expression will capture all whitespace-delimited content between delimiters
-       as a list of separate values.
-
-       Use the C{ignoreExpr} argument to define expressions that may contain
-       opening or closing characters that should not be treated as opening
-       or closing characters for nesting, such as quotedString or a comment
-       expression.  Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}.
-       The default is L{quotedString}, but if no expressions are to be ignored,
-       then pass C{None} for this argument.
-    """
-    if opener == closer:
-        raise ValueError("opening and closing strings cannot be the same")
-    if content is None:
-        if isinstance(opener,basestring) and isinstance(closer,basestring):
-            if len(opener) == 1 and len(closer)==1:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr +
-                                    CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
-                                ).setParseAction(lambda t:t[0].strip()))
-            else:
-                if ignoreExpr is not None:
-                    content = (Combine(OneOrMore(~ignoreExpr + 
-                                    ~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-                else:
-                    content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
-                                    CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
-                                ).setParseAction(lambda t:t[0].strip()))
-        else:
-            raise ValueError("opening and closing arguments must be strings if no content expression is given")
-    ret = Forward()
-    if ignoreExpr is not None:
-        ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
-    else:
-        ret << Group( Suppress(opener) + ZeroOrMore( ret | content )  + Suppress(closer) )
-    return ret
-
-def indentedBlock(blockStatementExpr, indentStack, indent=True):
-    """Helper method for defining space-delimited indentation blocks, such as
-       those used to define block statements in Python source code.
-
-       Parameters:
-        - blockStatementExpr - expression defining syntax of statement that
-            is repeated within the indented block
-        - indentStack - list created by caller to manage indentation stack
-            (multiple statementWithIndentedBlock expressions within a single grammar
-            should share a common indentStack)
-        - indent - boolean indicating whether block must be indented beyond the
-            the current level; set to False for block of left-most statements
-            (default=True)
-
-       A valid block must contain at least one C{blockStatement}.
-    """
-    def checkPeerIndent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if curCol != indentStack[-1]:
-            if curCol > indentStack[-1]:
-                raise ParseFatalException(s,l,"illegal nesting")
-            raise ParseException(s,l,"not a peer entry")
-
-    def checkSubIndent(s,l,t):
-        curCol = col(l,s)
-        if curCol > indentStack[-1]:
-            indentStack.append( curCol )
-        else:
-            raise ParseException(s,l,"not a subentry")
-
-    def checkUnindent(s,l,t):
-        if l >= len(s): return
-        curCol = col(l,s)
-        if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
-            raise ParseException(s,l,"not an unindent")
-        indentStack.pop()
-
-    NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
-    INDENT = Empty() + Empty().setParseAction(checkSubIndent)
-    PEER   = Empty().setParseAction(checkPeerIndent)
-    UNDENT = Empty().setParseAction(checkUnindent)
-    if indent:
-        smExpr = Group( Optional(NL) +
-            #~ FollowedBy(blockStatementExpr) +
-            INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
-    else:
-        smExpr = Group( Optional(NL) +
-            (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
-    blockStatementExpr.ignore(_bslash + LineEnd())
-    return smExpr
-
-alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
-punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
-
-anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
-commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
-_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
-replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
-
-# it's easy to get these comment structures wrong - they're very common, so may as well make them available
-cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
-
-htmlComment = Regex(r"<!--[\s\S]*?-->")
-restOfLine = Regex(r".*").leaveWhitespace()
-dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
-cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
-
-javaStyleComment = cppStyleComment
-pythonStyleComment = Regex(r"#.*").setName("Python style comment")
-_noncomma = "".join( [ c for c in printables if c != "," ] )
-_commasepitem = Combine(OneOrMore(Word(_noncomma) +
-                                  Optional( Word(" \t") +
-                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
-commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList")
-
-
-if __name__ == "__main__":
-
-    def test( teststring ):
-        try:
-            tokens = simpleSQL.parseString( teststring )
-            tokenlist = tokens.asList()
-            print (teststring + "->"   + str(tokenlist))
-            print ("tokens = "         + str(tokens))
-            print ("tokens.columns = " + str(tokens.columns))
-            print ("tokens.tables = "  + str(tokens.tables))
-            print (tokens.asXML("SQL",True))
-        except ParseBaseException as err:
-            print (teststring + "->")
-            print (err.line)
-            print (" "*(err.column-1) + "^")
-            print (err)
-        print()
-
-    selectToken    = CaselessLiteral( "select" )
-    fromToken      = CaselessLiteral( "from" )
-
-    ident          = Word( alphas, alphanums + "_$" )
-    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
-    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
-    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
-    simpleSQL      = ( selectToken + \
-                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
-                     fromToken + \
-                     tableNameList.setResultsName( "tables" ) )
-
-    test( "SELECT * from XYZZY, ABC" )
-    test( "select * from SYS.XYZZY" )
-    test( "Select A from Sys.dual" )
-    test( "Select AA,BB,CC from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Select A, B, C from Sys.dual" )
-    test( "Xelect A, B, C from Sys.dual" )
-    test( "Select A, B, C frox Sys.dual" )
-    test( "Select" )
-    test( "Select ^^^ frox Sys.dual" )
-    test( "Select A, B, C from Sys.dual, Table2   " )
diff --git a/src/setup.py b/src/setup.py
deleted file mode 100644
--- a/src/setup.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-
-"""Setup script for the pyparsing module distribution."""
-from distutils.core import setup
-
-import sys
-import os
-
-_PY3 = sys.version_info[0] > 2
-
-if _PY3:
-    from pyparsing_py3 import __version__ as pyparsing_version
-else:
-    from pyparsing_py2 import __version__ as pyparsing_version
-    
-modules = ["pyparsing",]
-
-# make sure that a pyparsing.py file exists - if not, copy the appropriate version
-def fileexists(fname):
-    try:
-        return bool(os.stat(fname))
-    except:
-        return False
-
-def copyfile(fromname, toname):
-    outf = open(toname,'w')
-    outf.write(open(fromname).read())
-    outf.close()
-    
-if "MAKING_PYPARSING_RELEASE" not in os.environ and not fileexists("pyparsing.py"):
-    if _PY3:
-        from_file = "pyparsing_py3.py"
-    else:
-        from_file = "pyparsing_py2.py"
-    copyfile(from_file, "pyparsing.py")
-
-setup(# Distribution meta-data
-    name = "pyparsing",
-    version = pyparsing_version,
-    description = "Python parsing module",
-    author = "Paul McGuire",
-    author_email = "ptmcg@users.sourceforge.net",
-    url = "http://pyparsing.wikispaces.com/",
-    download_url = "http://sourceforge.net/project/showfiles.php?group_id=97203",
-    license = "MIT License",
-    py_modules = modules,
-    classifiers=[
-        'Development Status :: 5 - Production/Stable',
-        'Intended Audience :: Developers',
-        'Intended Audience :: Information Technology',
-        'License :: OSI Approved :: MIT License',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 3',
-        ]
-    )
diff --git a/src/unitTests.py b/src/unitTests.py
deleted file mode 100644
--- a/src/unitTests.py
+++ /dev/null
@@ -1,2375 +0,0 @@
-# -*- coding: UTF-8 -*-
-from unittest import TestCase, TestSuite, TextTestRunner
-import unittest
-from pyparsing import ParseException
-import HTMLTestRunner
-
-import sys
-import pprint
-import pdb
-
-# see which Python implementation we are running
-CPYTHON_ENV = (sys.platform == "win32")
-IRON_PYTHON_ENV = (sys.platform == "cli")
-JYTHON_ENV = sys.platform.startswith("java")
-
-TEST_USING_PACKRAT = True
-#~ TEST_USING_PACKRAT = False
-
-# simple utility for flattening nested lists
-def flatten(L):
-    if type(L) is not list: return [L]
-    if L == []: return L
-    return flatten(L[0]) + flatten(L[1:])
-
-"""
-class ParseTest(TestCase):
-    def setUp(self):
-        pass
-        
-    def runTest(self):
-        assert 1==1, "we've got bigger problems..."
-        
-    def tearDown(self):
-        pass
-"""
-
-class ParseTestCase(TestCase):
-    def setUp(self):
-        print ">>>> Starting test",str(self)
-    
-    def runTest(self):
-        pass
-        
-    def tearDown(self):
-        print "<<<< End of test",str(self)
-        print  
-        
-    def __str__(self):
-        return self.__class__.__name__
-        
-class PyparsingTestInit(ParseTestCase):
-    def setUp(self):
-        from pyparsing import __version__ as pyparsingVersion
-        print "Beginning test of pyparsing, version", pyparsingVersion
-        print "Python version", sys.version
-    def tearDown(self):
-        pass
-        
-class ParseASMLTest(ParseTestCase):
-    def runTest(self):
-        import parseASML
-        files = [ ("A52759.txt", 2150, True, True, 0.38, 25, "21:47:17", "22:07:32", 235),
-                  ("24141506_P5107RM59_399A1457N1_PHS04", 373,True, True, 0.5, 1, "11:35:25", "11:37:05", 183),
-                  ("24141506_P5107RM59_399A1457N1_PHS04B", 373, True, True, 0.5, 1, "01:02:54", "01:04:49", 186),
-                  ("24157800_P5107RM74_399A1828M1_PHS04", 1141, True, False, 0.5, 13, "00:00:54", "23:59:48", 154) ]
-        for testFile,numToks,trkInpUsed,trkOutpUsed,maxDelta,numWafers,minProcBeg,maxProcEnd,maxLevStatsIV in files:
-            print "Parsing",testFile,"...",
-            #~ text = "\n".join( [ line for line in file(testFile) ] )
-            #~ results = parseASML.BNF().parseString( text )
-            results = parseASML.BNF().parseFile( testFile )
-            #~ pprint.pprint( results.asList() )
-            #~ pprint.pprint( results.batchData.asList() )
-            #~ print results.batchData.keys()
-                    
-            allToks = flatten( results.asList() )
-            assert len(allToks) == numToks, \
-                "wrong number of tokens parsed (%s), got %d, expected %d" % (testFile, len(allToks),numToks)
-            assert results.batchData.trackInputUsed == trkInpUsed, "error evaluating results.batchData.trackInputUsed"
-            assert results.batchData.trackOutputUsed == trkOutpUsed, "error evaluating results.batchData.trackOutputUsed"
-            assert results.batchData.maxDelta == maxDelta,"error evaluating results.batchData.maxDelta"
-            assert len(results.waferData) == numWafers, "did not read correct number of wafers"
-            assert min([wd.procBegin for wd in results.waferData]) == minProcBeg, "error reading waferData.procBegin"
-            assert max([results.waferData[k].procEnd for k in range(len(results.waferData))]) == maxProcEnd, "error reading waferData.procEnd"
-            assert sum(results.levelStatsIV['MAX']) == maxLevStatsIV, "error reading levelStatsIV"
-            assert sum(results.levelStatsIV.MAX) == maxLevStatsIV, "error reading levelStatsIV"
-            print "OK"
-            print testFile,len(allToks)
-            #~ print "results.batchData.trackInputUsed =",results.batchData.trackInputUsed
-            #~ print "results.batchData.trackOutputUsed =",results.batchData.trackOutputUsed
-            #~ print "results.batchData.maxDelta =",results.batchData.maxDelta
-            #~ print len(results.waferData)," wafers"
-            #~ print min([wd.procBegin for wd in results.waferData])
-            #~ print max([results.waferData[k].procEnd for k in range(len(results.waferData))])
-            #~ print sum(results.levelStatsIV['MAX.'])
-        
-
-class ParseFourFnTest(ParseTestCase):
-    def runTest(self):
-        import fourFn
-        def test(s,ans):
-            fourFn.exprStack = []
-            results = fourFn.BNF().parseString( s )
-            resultValue = fourFn.evaluateStack( fourFn.exprStack )
-            assert resultValue == ans, "failed to evaluate %s, got %f" % ( s, resultValue )
-            print s, "->", resultValue
-            
-        test( "9", 9 )
-        test( "9 + 3 + 6", 18 )
-        test( "9 + 3 / 11", 9.0+3.0/11.0)
-        test( "(9 + 3)", 12 )
-        test( "(9+3) / 11", (9.0+3.0)/11.0 )
-        test( "9 - (12 - 6)", 3)
-        test( "2*3.14159", 6.28318)
-        test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535/10.0 )
-        test( "PI * PI / 10", 3.1415926535*3.1415926535/10.0 )
-        test( "PI*PI/10", 3.1415926535*3.1415926535/10.0 )
-        test( "6.02E23 * 8.048", 6.02E23 * 8.048 )
-        test( "e / 3", 2.718281828/3.0 )
-        test( "sin(PI/2)", 1.0 )
-        test( "trunc(E)", 2.0 )
-        test( "E^PI", 2.718281828**3.1415926535 )
-        test( "2^3^2", 2**3**2)
-        test( "2^3+2", 2**3+2)
-        test( "2^9", 2**9 )
-        test( "sgn(-2)", -1 )
-        test( "sgn(0)", 0 )
-        test( "sgn(0.1)", 1 )
-
-class ParseSQLTest(ParseTestCase):
-    def runTest(self):
-        import simpleSQL
-        
-        def test(s, numToks, errloc=-1 ):
-            try:
-                sqlToks = flatten( simpleSQL.simpleSQL.parseString(s).asList() )
-                print s,sqlToks,len(sqlToks)
-                assert len(sqlToks) == numToks
-            except ParseException, e:
-                if errloc >= 0:
-                    assert e.loc == errloc
-                    
-            
-        test( "SELECT * from XYZZY, ABC", 6 )
-        test( "select * from SYS.XYZZY", 5 )
-        test( "Select A from Sys.dual", 5 )
-        test( "Select A,B,C from Sys.dual", 7 )
-        test( "Select A, B, C from Sys.dual", 7 )
-        test( "Select A, B, C from Sys.dual, Table2   ", 8 )
-        test( "Xelect A, B, C from Sys.dual", 0, 0 )
-        test( "Select A, B, C frox Sys.dual", 0, 15 )
-        test( "Select", 0, 6 )
-        test( "Select &&& frox Sys.dual", 0, 7 )
-        test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE')", 12 )
-        test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)", 20 )
-        test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators", 10 )
-
-class ParseConfigFileTest(ParseTestCase):
-    def runTest(self):
-        import configParse
-        
-        def test(fnam,numToks,resCheckList):
-            print "Parsing",fnam,"...",
-            iniFileLines = "\n".join([ lin for lin in file(fnam) ])
-            iniData = configParse.inifile_BNF().parseString( iniFileLines )
-            print len(flatten(iniData.asList()))
-            #~ pprint.pprint( iniData.asList() )
-            #~ pprint.pprint( repr(iniData) )
-            #~ print len(iniData), len(flatten(iniData.asList()))
-            print iniData.keys()
-            #~ print iniData.users.keys()
-            #~ print
-            assert len(flatten(iniData.asList())) == numToks, "file %s not parsed correctly" % fnam
-            for chk in resCheckList:
-                print chk[0], eval("iniData."+chk[0]), chk[1]
-                assert eval("iniData."+chk[0]) == chk[1]
-            print "OK"
-            
-        test("karthik.ini", 23, 
-                [ ("users.K","8"), 
-                  ("users.mod_scheme","'QPSK'"),
-                  ("users.Na", "K+2") ]
-                  )
-        test("setup.ini", 125, 
-                [ ("Startup.audioinf", "M3i"),
-                  ("Languages.key1", "0x0003"),
-                  ("test.foo","bar") ] )
-
-class ParseJSONDataTest(ParseTestCase):
-    def runTest(self):
-        from jsonParser import jsonObject
-        from jsonParserFull import test1,test2,test3,test4,test5
-        
-        expected = [
-            [],
-            [],
-            [],
-            [],
-            [],
-            ]
-            
-        import pprint
-        for t,exp in zip((test1,test2,test3,test4,test5),expected):
-            result = jsonObject.parseString(t)
-##            print result.dump()
-            pprint.pprint(result.asList())
-            print
-##            if result.asList() != exp:
-##                print "Expected %s, parsed results as %s" % (exp, result.asList())
-
-class ParseCommaSeparatedValuesTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import commaSeparatedList
-        import string
-        
-        testData = [
-            "a,b,c,100.2,,3",
-            "d, e, j k , m  ",
-            "'Hello, World', f, g , , 5.1,x",
-            "John Doe, 123 Main St., Cleveland, Ohio",
-            "Jane Doe, 456 St. James St., Los Angeles , California   ",
-            "",
-            ]
-        testVals = [
-            [ (3,'100.2'), (4,''), (5, '3') ],
-            [ (2, 'j k'), (3, 'm') ],
-            [ (0, "'Hello, World'"), (2, 'g'), (3, '') ],
-            [ (0,'John Doe'), (1, '123 Main St.'), (2, 'Cleveland'), (3, 'Ohio') ], 
-            [ (0,'Jane Doe'), (1, '456 St. James St.'), (2, 'Los Angeles'), (3, 'California') ]
-            ]
-        for line,tests in zip(testData, testVals):
-            print "Parsing: \""+line+"\" ->",
-            results = commaSeparatedList.parseString(line)
-            print results.asList()
-            for t in tests:
-                if not(len(results)>t[0] and results[t[0]] == t[1]):
-                    print "$$$", results.dump()
-                    print "$$$", results[0]
-                assert len(results)>t[0] and results[t[0]] == t[1],"failed on %s, item %d s/b '%s', got '%s'" % ( line, t[0], t[1], str(results.asList()) )
-
-class ParseEBNFTest(ParseTestCase):
-    def runTest(self):
-        import ebnf
-        from pyparsing import Word, quotedString, alphas, nums,ParserElement
-        
-        print 'Constructing EBNF parser with pyparsing...'
-        
-        grammar = '''
-        syntax = (syntax_rule), {(syntax_rule)};
-        syntax_rule = meta_identifier, '=', definitions_list, ';';
-        definitions_list = single_definition, {'|', single_definition};
-        single_definition = syntactic_term, {',', syntactic_term};
-        syntactic_term = syntactic_factor,['-', syntactic_factor];
-        syntactic_factor = [integer, '*'], syntactic_primary;
-        syntactic_primary = optional_sequence | repeated_sequence |
-          grouped_sequence | meta_identifier | terminal_string;
-        optional_sequence = '[', definitions_list, ']';
-        repeated_sequence = '{', definitions_list, '}';
-        grouped_sequence = '(', definitions_list, ')';
-        (* 
-        terminal_string = "'", character - "'", {character - "'"}, "'" |
-          '"', character - '"', {character - '"'}, '"';
-         meta_identifier = letter, {letter | digit};
-        integer = digit, {digit}; 
-        *)
-        '''
-        
-        table = {}
-        table['terminal_string'] = quotedString
-        table['meta_identifier'] = Word(alphas+"_", alphas+"_"+nums)
-        table['integer'] = Word(nums)
-        
-        print 'Parsing EBNF grammar with EBNF parser...'
-        parsers = ebnf.parse(grammar, table)
-        ebnf_parser = parsers['syntax']
-        #~ print ",\n ".join( str(parsers.keys()).split(", ") )
-        print "-","\n- ".join( parsers.keys() )
-        assert len(parsers.keys()) == 13, "failed to construct syntax grammar"
-
-        print 'Parsing EBNF grammar with generated EBNF parser...'
-        parsed_chars = ebnf_parser.parseString(grammar)
-        parsed_char_len = len(parsed_chars)
-        
-        print "],\n".join(str( parsed_chars.asList() ).split("],"))
-        assert len(flatten(parsed_chars.asList())) == 98, "failed to tokenize grammar correctly"
-        
-
-class ParseIDLTest(ParseTestCase):
-    def runTest(self):
-        import idlParse
-
-        def test( strng, numToks, errloc=0 ):
-            print strng
-            try:
-                bnf = idlParse.CORBA_IDL_BNF()
-                tokens = bnf.parseString( strng )
-                print "tokens = "
-                pprint.pprint( tokens.asList() )
-                tokens = flatten( tokens.asList() )
-                print len(tokens)
-                assert len(tokens) == numToks, "error matching IDL string, %s -> %s" % (strng, str(tokens) )
-            except ParseException, err:
-                print err.line
-                print " "*(err.column-1) + "^"
-                print err
-                assert numToks == 0, "unexpected ParseException while parsing %s, %s" % (strng, str(err) )
-                assert err.loc == errloc, "expected ParseException at %d, found exception at %d" % (errloc, err.loc)
-            
-        test(
-            """
-            /*
-             * a block comment *
-             */
-            typedef string[10] tenStrings;
-            typedef sequence<string> stringSeq;
-            typedef sequence< sequence<string> > stringSeqSeq;
-            
-            interface QoSAdmin {
-                stringSeq method1( in string arg1, inout long arg2 );
-                stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
-                string method3();
-              };
-            """, 59
-            )
-        test(
-            """
-            /*
-             * a block comment *
-             */
-            typedef string[10] tenStrings;
-            typedef 
-                /** ** *** **** *
-                 * a block comment *
-                 */
-                sequence<string> /*comment inside an And */ stringSeq;
-            /* */  /**/ /***/ /****/
-            typedef sequence< sequence<string> > stringSeqSeq;
-            
-            interface QoSAdmin {
-                stringSeq method1( in string arg1, inout long arg2 );
-                stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
-                string method3();
-              };
-            """, 59
-            )
-        test(
-            r"""
-              const string test="Test String\n";
-              const long  a = 0;
-              const long  b = -100;
-              const float c = 3.14159;
-              const long  d = 0x007f7f7f;
-              exception TestException
-                {
-                string msg;
-                sequence<string> dataStrings;
-                };
-              
-              interface TestInterface
-                {
-                void method1( in string arg1, inout long arg2 );
-                };
-            """, 60
-            )
-        test(
-            """
-            module Test1 
-              {
-              exception TestException
-                {
-                string msg;
-                ];
-              
-              interface TestInterface
-                {
-                void method1( in string arg1, inout long arg2 ) 
-                  raises ( TestException );
-                };
-              };
-            """, 0, 57
-            )
-        test(
-            """
-            module Test1 
-              {
-              exception TestException
-                {
-                string msg;
-                };
-        
-              };
-            """, 13
-            )
-    
-class ParseVerilogTest(ParseTestCase):
-    def runTest(self):
-        pass
-
-class RunExamplesTest(ParseTestCase):
-    def runTest(self):
-        pass
-        
-class ScanStringTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word, Combine, Suppress, CharsNotIn, nums, StringEnd
-        testdata = """
-            <table border="0" cellpadding="3" cellspacing="3" frame="" width="90%">
-                <tr align="left" valign="top">
-                        <td><b>Name</b></td>
-                        <td><b>IP Address</b></td>
-                        <td><b>Location</b></td>
-                </tr>
-                <tr align="left" valign="top" bgcolor="#c7efce">
-                        <td>time-a.nist.gov</td>
-                        <td>129.6.15.28</td>
-                        <td>NIST, Gaithersburg, Maryland</td>
-                </tr>
-                <tr align="left" valign="top">
-                        <td>time-b.nist.gov</td>
-                        <td>129.6.15.29</td>
-                        <td>NIST, Gaithersburg, Maryland</td>
-                </tr>
-                <tr align="left" valign="top" bgcolor="#c7efce">
-                        <td>time-a.timefreq.bldrdoc.gov</td>
-                        <td>132.163.4.101</td>
-                        <td>NIST, Boulder, Colorado</td>
-                </tr>
-                <tr align="left" valign="top">
-                        <td>time-b.timefreq.bldrdoc.gov</td>
-                        <td>132.163.4.102</td>
-                        <td>NIST, Boulder, Colorado</td>
-                </tr>
-                <tr align="left" valign="top" bgcolor="#c7efce">
-                        <td>time-c.timefreq.bldrdoc.gov</td>
-                        <td>132.163.4.103</td>
-                        <td>NIST, Boulder, Colorado</td>
-                </tr>
-            </table>
-            """
-        integer = Word(nums)
-        ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer )
-        tdStart = Suppress("<td>")
-        tdEnd = Suppress("</td>")
-        timeServerPattern =  tdStart + ipAddress.setResultsName("ipAddr") + tdEnd + \
-                tdStart + CharsNotIn("<").setResultsName("loc") + tdEnd
-        servers = \
-            [ srvr.ipAddr for srvr,startloc,endloc in timeServerPattern.scanString( testdata ) ]
-            
-        print servers
-        assert servers == ['129.6.15.28', '129.6.15.29', '132.163.4.101', '132.163.4.102', '132.163.4.103'], \
-            "failed scanString()"
-        
-        # test for stringEnd detection in scanString
-        foundStringEnds = [ r for r in StringEnd().scanString("xyzzy") ]
-        print foundStringEnds
-        assert foundStringEnds, "Failed to find StringEnd in scanString"
-            
-class QuotedStringsTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import sglQuotedString,dblQuotedString,quotedString
-        testData = \
-            """
-                'a valid single quoted string'
-                'an invalid single quoted string
-                 because it spans lines'
-                "a valid double quoted string"
-                "an invalid double quoted string
-                 because it spans lines"
-            """
-        print testData
-        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(testData) ]
-        print sglStrings
-        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==47), \
-            "single quoted string failure"
-        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(testData) ]
-        print dblStrings
-        assert len(dblStrings) == 1 and (dblStrings[0][1]==154 and dblStrings[0][2]==184), \
-            "double quoted string failure"
-        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(testData) ]
-        print allStrings
-        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==47) and \
-                                         (allStrings[1][1]==154 and allStrings[1][2]==184), \
-            "quoted string failure"
-        
-        escapedQuoteTest = \
-            r"""
-                'This string has an escaped (\') quote character'
-                "This string has an escaped (\") quote character"
-            """
-        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(escapedQuoteTest) ]
-        print sglStrings
-        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \
-            "single quoted string escaped quote failure (%s)" % str(sglStrings[0])
-        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(escapedQuoteTest) ]
-        print dblStrings
-        assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \
-            "double quoted string escaped quote failure (%s)" % str(dblStrings[0])
-        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(escapedQuoteTest) ]
-        print allStrings
-        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and
-                                          allStrings[1][1]==83 and allStrings[1][2]==132), \
-            "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])
-        
-        dblQuoteTest = \
-            r"""
-                'This string has an doubled ('') quote character'
-                "This string has an doubled ("") quote character"
-            """
-        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(dblQuoteTest) ]
-        print sglStrings
-        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \
-            "single quoted string escaped quote failure (%s)" % str(sglStrings[0])
-        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(dblQuoteTest) ]
-        print dblStrings
-        assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \
-            "double quoted string escaped quote failure (%s)" % str(dblStrings[0])
-        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(dblQuoteTest) ]
-        print allStrings
-        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and
-                                          allStrings[1][1]==83 and allStrings[1][2]==132), \
-            "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])
-        
-class CaselessOneOfTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import oneOf,ZeroOrMore
-        
-        caseless1 = oneOf("d a b c aA B A C", caseless=True)
-        caseless1str = str( caseless1 )
-        print caseless1str
-        caseless2 = oneOf("d a b c Aa B A C", caseless=True)
-        caseless2str = str( caseless2 )
-        print caseless2str
-        assert caseless1str.upper() == caseless2str.upper(), "oneOf not handling caseless option properly"
-        assert caseless1str != caseless2str, "Caseless option properly sorted"
-        
-        res = ZeroOrMore(caseless1).parseString("AAaaAaaA")
-        print res
-        assert len(res) == 4, "caseless1 oneOf failed"
-        assert "".join(res) == "aA"*4,"caseless1 CaselessLiteral return failed"
-        
-        res = ZeroOrMore(caseless2).parseString("AAaaAaaA")
-        print res
-        assert len(res) == 4, "caseless2 oneOf failed"
-        assert "".join(res) == "Aa"*4,"caseless1 CaselessLiteral return failed"
-        
-
-class AsXMLTest(ParseTestCase):
-    def runTest(self):
-        
-        import pyparsing
-        # test asXML()
-        
-        aaa = pyparsing.Word("a").setResultsName("A")
-        bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B")
-        ccc = pyparsing.Combine(":" + pyparsing.Word("c")).setResultsName("C")
-        g1 = "XXX>&<" + pyparsing.ZeroOrMore( aaa | bbb | ccc )
-        teststring = "XXX>&< b b a b b a b :c b a"
-        #~ print teststring
-        print "test including all items"
-        xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=False)
-        assert xml=="\n".join(["",
-                                "<TEST>",
-                                "  <ITEM>XXX&gt;&amp;&lt;</ITEM>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <C>:c</C>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "</TEST>",
-                                ] ), \
-            "failed to generate XML correctly showing all items: \n[" + xml + "]"
-        print "test filtering unnamed items"
-        xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=True)
-        assert xml=="\n".join(["",
-                                "<TEST>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <C>:c</C>",
-                                "  <B>",
-                                "    <ITEM>b</ITEM>",
-                                "  </B>",
-                                "  <A>a</A>",
-                                "</TEST>", 
-                                ] ), \
-            "failed to generate XML correctly, filtering unnamed items: " + xml
-
-class AsXMLTest2(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Suppress,Optional,CharsNotIn,Combine,ZeroOrMore,Word,\
-            Group,Literal,alphas,alphanums,delimitedList,OneOrMore
-        
-        EndOfLine = Word("\n").setParseAction(lambda s,l,t: [' '])
-        whiteSpace=Word('\t ')
-        Mexpr = Suppress(Optional(whiteSpace)) + CharsNotIn('\\"\t \n') + Optional(" ") + \
-                Suppress(Optional(whiteSpace))
-        reducedString = Combine(Mexpr + ZeroOrMore(EndOfLine + Mexpr))
-        _bslash = "\\"
-        _escapables = "tnrfbacdeghijklmopqsuvwxyz" + _bslash + "'" + '"'
-        _octDigits = "01234567"
-        _escapedChar = ( Word( _bslash, _escapables, exact=2 ) |
-                         Word( _bslash, _octDigits, min=2, max=4 ) )
-        _sglQuote = Literal("'")
-        _dblQuote = Literal('"')
-        QuotedReducedString = Combine( Suppress(_dblQuote) + ZeroOrMore( reducedString |
-                                                                         _escapedChar ) + \
-                                       Suppress(_dblQuote )).streamline()
-        
-        Manifest_string = QuotedReducedString.setResultsName('manifest_string')
-        
-        Identifier  = Word( alphas, alphanums+ '_$' ).setResultsName("identifier")
-        Index_string = CharsNotIn('\\";\n')
-        Index_string.setName('index_string')
-        Index_term_list = (
-                Group(delimitedList(Manifest_string, delim=',')) | \
-                Index_string
-                ).setResultsName('value')
-        
-        IndexKey = Identifier.setResultsName('key')
-        IndexKey.setName('key')
-        Index_clause = Group(IndexKey + Suppress(':') + Optional(Index_term_list))
-        Index_clause.setName('index_clause')
-        Index_list = Index_clause.setResultsName('index') 
-        Index_list.setName('index_list')
-        Index_block = Group('indexing' + Group(OneOrMore(Index_list + Suppress(';')))).setResultsName('indexes')
-        
-
-class CommentParserTest(ParseTestCase):
-    def runTest(self):
-        import pyparsing
-        print "verify processing of C and HTML comments"
-        testdata = """
-        /* */
-        /** **/
-        /**/
-        /***/
-        /****/
-        /* /*/
-        /** /*/
-        /*** /*/
-        /* 
-         ablsjdflj
-         */
-        """
-        foundLines = [ pyparsing.lineno(s,testdata)
-            for t,s,e in pyparsing.cStyleComment.scanString(testdata) ]
-        assert foundLines == range(11)[2:],"only found C comments on lines "+str(foundLines)
-        testdata = """
-        <!-- -->
-        <!--- --->
-        <!---->
-        <!----->
-        <!------>
-        <!-- /-->
-        <!--- /-->
-        <!---- /-->
-        <!---- /- ->
-        <!---- / -- >
-        <!-- 
-         ablsjdflj
-         -->
-        """
-        foundLines = [ pyparsing.lineno(s,testdata)
-            for t,s,e in pyparsing.htmlComment.scanString(testdata) ]
-        assert foundLines == range(11)[2:],"only found HTML comments on lines "+str(foundLines)
-
-        # test C++ single line comments that have line terminated with '\' (should continue comment to following line)
-        testSource = r"""
-            // comment1
-            // comment2 \
-            still comment 2
-            // comment 3
-            """
-        assert len(pyparsing.cppStyleComment.searchString(testSource)[1][0]) == 41, r"failed to match single-line comment with '\' at EOL"
-
-class ParseExpressionResultsTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word,alphas,OneOrMore,Optional,Group
-
-        a = Word("a",alphas).setName("A")
-        b = Word("b",alphas).setName("B")
-        c = Word("c",alphas).setName("C")
-        ab = (a + b).setName("AB")
-        abc = (ab + c).setName("ABC")
-        word = Word(alphas).setName("word")
-        
-        #~ words = OneOrMore(word).setName("words")
-        words = Group(OneOrMore(~a + word)).setName("words")
-        
-        #~ phrase = words.setResultsName("Head") + \
-                    #~ ( abc ^ ab ^ a ).setResultsName("ABC") + \
-                    #~ words.setResultsName("Tail")
-        #~ phrase = words.setResultsName("Head") + \
-                    #~ ( abc | ab | a ).setResultsName("ABC") + \
-                    #~ words.setResultsName("Tail")
-        phrase = words.setResultsName("Head") + \
-                    Group( a + Optional(b + Optional(c)) ).setResultsName("ABC") + \
-                    words.setResultsName("Tail")
-        
-        results = phrase.parseString("xavier yeti alpha beta charlie will beaver")
-        print results,results.Head, results.ABC,results.Tail
-        for key,ln in [("Head",2), ("ABC",3), ("Tail",2)]:
-            #~ assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key].asList()))
-            assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key]))
-        
-
-class ParseKeywordTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Literal,Keyword
-        
-        kw = Keyword("if")
-        lit = Literal("if")
-        
-        def test(s,litShouldPass,kwShouldPass):
-            print "Test",s
-            print "Match Literal",
-            try:
-                print lit.parseString(s)
-            except:
-                print "failed"
-                if litShouldPass: assert False, "Literal failed to match %s, should have" % s
-            else:
-                if not litShouldPass: assert False, "Literal matched %s, should not have" % s
-        
-            print "Match Keyword",
-            try:
-                print kw.parseString(s)
-            except:
-                print "failed"
-                if kwShouldPass: assert False, "Keyword failed to match %s, should have" % s
-            else:
-                if not kwShouldPass: assert False, "Keyword matched %s, should not have" % s
-        
-        test("ifOnlyIfOnly", True, False)
-        test("if(OnlyIfOnly)", True, True)
-        test("if (OnlyIf Only)", True, True)
-        
-        kw = Keyword("if",caseless=True)
-        
-        test("IFOnlyIfOnly", False, False)
-        test("If(OnlyIfOnly)", False, True)
-        test("iF (OnlyIf Only)", False, True)
-
-
-
-class ParseExpressionResultsAccumulateTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word,delimitedList,Combine,alphas,nums
-
-        num=Word(nums).setName("num").setResultsName("base10", listAllMatches=True)
-        hexnum=Combine("0x"+ Word(nums)).setName("hexnum").setResultsName("hex", listAllMatches=True)
-        name = Word(alphas).setName("word").setResultsName("word", listAllMatches=True)
-        list_of_num=delimitedList( hexnum | num | name, "," )
-        
-        tokens = list_of_num.parseString('1, 0x2, 3, 0x4, aaa')
-        for k,llen,lst in ( ("base10",2,['1','3']),
-                             ("hex",2,['0x2','0x4']),
-                             ("word",1,['aaa']) ):
-            print k,tokens[k]
-            assert len(tokens[k]) == llen, "Wrong length for key %s, %s" % (k,str(tokens[k].asList()))
-            assert lst == tokens[k].asList(), "Incorrect list returned for key %s, %s" % (k,str(tokens[k].asList()))
-        assert tokens.base10.asList() == ['1','3'], "Incorrect list for attribute base10, %s" % str(tokens.base10.asList())
-        assert tokens.hex.asList() == ['0x2','0x4'], "Incorrect list for attribute hex, %s" % str(tokens.hex.asList())
-        assert tokens.word.asList() == ['aaa'], "Incorrect list for attribute word, %s" % str(tokens.word.asList())
-
-        from pyparsing import Literal, Word, nums, Group, Dict, alphas, \
-            quotedString, oneOf, delimitedList, removeQuotes, alphanums
-
-        lbrack = Literal("(").suppress()
-        rbrack = Literal(")").suppress()
-        integer = Word( nums ).setName("int")
-        variable = Word( alphas, max=1 ).setName("variable")
-        relation_body_item = variable | integer | quotedString.copy().setParseAction(removeQuotes)
-        relation_name = Word( alphas+"_", alphanums+"_" )
-        relation_body = lbrack + Group(delimitedList(relation_body_item)) + rbrack
-        Goal = Dict(Group( relation_name + relation_body ))
-        Comparison_Predicate = Group(variable + oneOf("< >") + integer).setResultsName("pred",listAllMatches=True)
-        Query = Goal.setResultsName("head") + ":-" + delimitedList(Goal | Comparison_Predicate)
-
-        test="""Q(x,y,z):-Bloo(x,"Mitsis",y),Foo(y,z,1243),y>28,x<12,x>3"""
-        
-        queryRes = Query.parseString(test)
-        print "pred",queryRes.pred
-        assert queryRes.pred.asList() == [['y', '>', '28'], ['x', '<', '12'], ['x', '>', '3']], "Incorrect list for attribute pred, %s" % str(queryRes.pred.asList())
-        print queryRes.dump()
-
-class ReStringRangeTest(ParseTestCase):
-    def runTest(self):
-        import pyparsing
-        testCases = (
-            (r"[A-Z]"),
-            (r"[A-A]"),
-            (r"[A-Za-z]"),
-            (r"[A-z]"),
-            (r"[\ -\~]"),
-            (r"[\0x20-0]"),
-            (r"[\0x21-\0x7E]"),
-            (r"[\0xa1-\0xfe]"),
-            (r"[\040-0]"),
-            (r"[A-Za-z0-9]"),
-            (r"[A-Za-z0-9_]"),
-            (r"[A-Za-z0-9_$]"),
-            (r"[A-Za-z0-9_$\-]"),
-            (r"[^0-9\\]"),
-            (r"[a-zA-Z]"),
-            (r"[/\^~]"),
-            (r"[=\+\-!]"),
-            (r"[A-]"),
-            (r"[-A]"),
-            )
-        expectedResults = (
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
-            "A",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz",
-            " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
-            " !\"#$%&'()*+,-./0",
-            "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
-            #~ "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ",
-            u'\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe',
-            " !\"#$%&'()*+,-./0",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$",
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$-",
-            "0123456789\\",
-            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
-            "/^~",
-            "=+-!",
-            "A-",
-            "-A",
-            )
-        for test in zip( testCases, expectedResults ):
-            t,exp = test
-            res = pyparsing.srange(t)
-            #~ print t,"->",res
-            assert res == exp, "srange error, srange(%s)->'%s', expected '%s'" % (t, res, exp)
-
-class SkipToParserTests(ParseTestCase):
-    def runTest(self):
-        
-        from pyparsing import Literal, SkipTo, NotAny, cStyleComment
-        
-        thingToFind = Literal('working')
-        testExpr = SkipTo(Literal(';'), True, cStyleComment) + thingToFind
-        
-        def tryToParse (someText):
-            try:
-                print testExpr.parseString(someText)
-            except Exception, e:
-                print "Exception %s while parsing string %s" % (e,repr(someText))
-                assert False, "Exception %s while parsing string %s" % (e,repr(someText))
-    
-        # This first test works, as the SkipTo expression is immediately following the ignore expression (cStyleComment)
-        tryToParse('some text /* comment with ; in */; working')
-        # This second test fails, as there is text following the ignore expression, and before the SkipTo expression.
-        tryToParse('some text /* comment with ; in */some other stuff; working')
-
-
-class CustomQuotesTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import QuotedString
-
-        testString = r"""
-            sdlfjs :sdf\:jls::djf: sl:kfsjf
-            sdlfjs -sdf\:jls::--djf: sl-kfsjf
-            sdlfjs -sdf\:::jls::--djf: sl:::-kfsjf
-            sdlfjs ^sdf\:jls^^--djf^ sl-kfsjf
-            sdlfjs ^^^==sdf\:j=lz::--djf: sl=^^=kfsjf
-            sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf^^^
-        """
-        colonQuotes = QuotedString(':','\\','::')
-        dashQuotes  = QuotedString('-','\\', '--')
-        hatQuotes   = QuotedString('^','\\')
-        hatQuotes1  = QuotedString('^','\\','^^')
-        dblEqQuotes = QuotedString('==','\\')
-        
-        def test(quoteExpr, expected):
-            print quoteExpr.pattern
-            print quoteExpr.searchString(testString)
-            print quoteExpr.searchString(testString)[0][0]
-            assert quoteExpr.searchString(testString)[0][0] == expected, \
-                    "failed to match %s, expected '%s', got '%s'" % \
-                    (quoteExpr,expected,quoteExpr.searchString(testString)[0])
-        
-        test(colonQuotes, r"sdf:jls:djf")
-        test(dashQuotes,  r"sdf\:jls::-djf: sl")
-        test(hatQuotes,   r"sdf\:jls")
-        test(hatQuotes1,  r"sdf\:jls^--djf")
-        test(dblEqQuotes, r"sdf\:j=ls::--djf: sl")
-        test( QuotedString(':::'), 'jls::--djf: sl')
-        test( QuotedString('==',endQuoteChar='--'), r'sdf\:j=lz::')
-        test( QuotedString('^^^',multiline=True), r"""==sdf\:j=lz::--djf: sl=^^=kfsjf
-            sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf""")
-        try:
-            bad1 = QuotedString('','\\')
-        except SyntaxError,se:
-            pass
-        else:
-            assert False,"failed to raise SyntaxError with empty quote string"
-
-class RepeaterTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import matchPreviousLiteral,matchPreviousExpr, Forward, Literal, Word, alphas, nums
-
-        first = Word("abcdef").setName("word1")
-        bridge = Word(nums).setName("number")
-        second = matchPreviousLiteral(first).setName("repeat(word1Literal)")
-
-        seq = first + bridge + second
-
-        tests = [
-            ( "abc12abc", True ),
-            ( "abc12aabc", False ),
-            ( "abc12cba", True ),
-            ( "abc12bca", True ),
-        ]
-
-        for tst,result in tests:
-            found = False
-            for tokens,start,end in seq.scanString(tst):
-                f,b,s = tokens
-                print f,b,s
-                found = True
-            if not found:
-                print "No literal match in", tst
-            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
-        print
-
-        # retest using matchPreviousExpr instead of matchPreviousLiteral
-        second = matchPreviousExpr(first).setName("repeat(word1expr)")
-        seq = first + bridge + second
-        
-        tests = [
-            ( "abc12abc", True ),
-            ( "abc12cba", False ),
-            ( "abc12abcdef", False ),
-            ]
-
-        for tst,result in tests:
-            found = False
-            for tokens,start,end in seq.scanString(tst):
-                print tokens.asList()
-                found = True
-            if not found:
-                print "No expression match in", tst
-            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
-            
-        print
-
-        first = Word("abcdef").setName("word1")
-        bridge = Word(nums).setName("number")
-        second = matchPreviousExpr(first).setName("repeat(word1)")
-        seq = first + bridge + second
-        csFirst = seq.setName("word-num-word")
-        csSecond = matchPreviousExpr(csFirst)
-        compoundSeq = csFirst + ":" + csSecond
-        compoundSeq.streamline()
-        print compoundSeq
-        
-        tests = [
-            ( "abc12abc:abc12abc", True ),
-            ( "abc12cba:abc12abc", False ),
-            ( "abc12abc:abc12abcdef", False ),
-            ]
-
-        #~ for tst,result in tests:
-            #~ print tst,
-            #~ try:
-                #~ compoundSeq.parseString(tst)
-                #~ print "MATCH"
-                #~ assert result, "matched when shouldn't have matched"
-            #~ except ParseException:
-                #~ print "NO MATCH"
-                #~ assert not result, "didnt match but should have"
-
-        #~ for tst,result in tests:
-            #~ print tst,
-            #~ if compoundSeq == tst:
-                #~ print "MATCH"
-                #~ assert result, "matched when shouldn't have matched"
-            #~ else:
-                #~ print "NO MATCH"
-                #~ assert not result, "didnt match but should have"
-
-        for tst,result in tests:
-            found = False
-            for tokens,start,end in compoundSeq.scanString(tst):
-                print "match:", tokens.asList()
-                found = True
-                break
-            if not found:
-                print "No expression match in", tst
-            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
-            
-        print
-        eFirst = Word(nums)
-        eSecond = matchPreviousExpr(eFirst)
-        eSeq = eFirst + ":" + eSecond
-        
-        tests = [
-            ( "1:1A", True ),
-            ( "1:10", False ),
-            ]
-        
-        for tst,result in tests:
-            found = False
-            for tokens,start,end in eSeq.scanString(tst):
-                #~ f,b,s = tokens
-                #~ print f,b,s
-                print tokens.asList()
-                found = True
-            if not found:
-                print "No match in", tst
-            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
-
-class RecursiveCombineTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Forward,Word,alphas,nums,Optional,Combine
-        
-        testInput = "myc(114)r(11)dd"
-        Stream=Forward()
-        Stream << Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream)
-        expected = Stream.parseString(testInput).asList()
-        print ["".join(expected)]
-
-        Stream=Forward()
-        Stream << Combine(Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream))
-        testVal = Stream.parseString(testInput).asList()
-        print testVal
-        
-        assert "".join(testVal) == "".join(expected), "Failed to process Combine with recursive content"
-
-class OperatorPrecedenceGrammarTest1(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word,nums,alphas,Literal,oneOf,operatorPrecedence,opAssoc
-        
-        integer = Word(nums).setParseAction(lambda t:int(t[0]))
-        variable = Word(alphas,exact=1)
-        operand = integer | variable
-
-        expop = Literal('^')
-        signop = oneOf('+ -')
-        multop = oneOf('* /')
-        plusop = oneOf('+ -')
-        factop = Literal('!')
-
-        expr = operatorPrecedence( operand,
-            [("!", 1, opAssoc.LEFT),
-             ("^", 2, opAssoc.RIGHT),
-             (signop, 1, opAssoc.RIGHT),
-             (multop, 2, opAssoc.LEFT),
-             (plusop, 2, opAssoc.LEFT),]
-            )
-
-        test = ["9 + 2 + 3",
-                "9 + 2 * 3",
-                "(9 + 2) * 3",
-                "(9 + -2) * 3",
-                "(9 + --2) * 3",
-                "(9 + -2) * 3^2^2",
-                "(9! + -2) * 3^2^2",
-                "M*X + B",
-                "M*(X + B)",
-                "1+2*-3^4*5+-+-6",
-                "3!!"]
-        expected = """[[9, '+', 2, '+', 3]]
-                    [[9, '+', [2, '*', 3]]]
-                    [[[9, '+', 2], '*', 3]]
-                    [[[9, '+', ['-', 2]], '*', 3]]
-                    [[[9, '+', ['-', ['-', 2]]], '*', 3]]
-                    [[[9, '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]]
-                    [[[[9, '!'], '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]]
-                    [[['M', '*', 'X'], '+', 'B']]
-                    [['M', '*', ['X', '+', 'B']]]
-                    [[1, '+', [2, '*', ['-', [3, '^', 4]], '*', 5], '+', ['-', ['+', ['-', 6]]]]]
-                    [[3, '!', '!']]""".split('\n')
-        expected = map(lambda x:eval(x),expected)
-        for t,e in zip(test,expected):
-            print t,"->",e, "got", expr.parseString(t).asList()
-            assert expr.parseString(t).asList() == e,"mismatched results for operatorPrecedence: got %s, expected %s" % (expr.parseString(t).asList(),e)
-
-class OperatorPrecedenceGrammarTest2(ParseTestCase):
-    def runTest(self):
-
-        from pyparsing import operatorPrecedence, Word, alphas, oneOf, opAssoc
-        
-        boolVars = { "True":True, "False":False }
-        class BoolOperand(object):
-            def __init__(self,t):
-                self.args = t[0][0::2]
-            def __str__(self):
-                sep = " %s " % self.reprsymbol
-                return "(" + sep.join(map(str,self.args)) + ")"
-            
-        class BoolAnd(BoolOperand):
-            reprsymbol = '&'
-            def __nonzero__(self):
-                for a in self.args:
-                    if isinstance(a,basestring):
-                        v = boolVars[a]
-                    else:
-                        v = bool(a)
-                    if not v:
-                        return False
-                return True
-
-        class BoolOr(BoolOperand):
-            reprsymbol = '|'    
-            def __nonzero__(self):
-                for a in self.args:
-                    if isinstance(a,basestring):
-                        v = boolVars[a]
-                    else:
-                        v = bool(a)
-                    if v:
-                        return True
-                return False
-
-        class BoolNot(BoolOperand):
-            def __init__(self,t):
-                self.arg = t[0][1]
-            def __str__(self):
-                return "~" + str(self.arg)
-            def __nonzero__(self):
-                if isinstance(self.arg,basestring):
-                    v = boolVars[self.arg]
-                else:
-                    v = bool(self.arg)
-                return not v
-
-        boolOperand = Word(alphas,max=1) | oneOf("True False")
-        boolExpr = operatorPrecedence( boolOperand,
-            [
-            ("not", 1, opAssoc.RIGHT, BoolNot),
-            ("and", 2, opAssoc.LEFT,  BoolAnd),
-            ("or",  2, opAssoc.LEFT,  BoolOr),
-            ])
-        test = ["p and not q",
-                "not not p",
-                "not(p and q)",
-                "q or not p and r",
-                "q or not p or not r",
-                "q or not (p and r)",
-                "p or q or r",
-                "p or q or r and False",
-                "(p or q or r) and False",
-                ]
-
-        boolVars["p"] = True
-        boolVars["q"] = False
-        boolVars["r"] = True
-        print "p =", boolVars["p"]
-        print "q =", boolVars["q"]
-        print "r =", boolVars["r"]
-        print
-        for t in test:
-            res = boolExpr.parseString(t)[0]
-            print t,'\n', res, '=', bool(res),'\n'
-
-        
-class OperatorPrecedenceGrammarTest3(ParseTestCase):
-    def runTest(self):
-
-        from pyparsing import operatorPrecedence, Word, alphas, oneOf, opAssoc, nums, Literal
-        
-        global count
-        count = 0
-        
-        def evaluate_int(t):
-            global count
-            value = int(t[0])
-            print "evaluate_int", value
-            count += 1
-            return value
-
-        integer = Word(nums).setParseAction(evaluate_int)
-        variable = Word(alphas,exact=1)
-        operand = integer | variable
-
-        expop = Literal('^')
-        signop = oneOf('+ -')
-        multop = oneOf('* /')
-        plusop = oneOf('+ -')
-        factop = Literal('!')
-
-        expr = operatorPrecedence( operand,
-            [
-            ("!", 1, opAssoc.LEFT),
-            ("^", 2, opAssoc.RIGHT),
-            (signop, 1, opAssoc.RIGHT),
-            (multop, 2, opAssoc.LEFT),
-            (plusop, 2, opAssoc.LEFT),
-            ])
-
-        test = ["9"]
-        for t in test:
-            count = 0
-            print "%s => %s" % (t, expr.parseString(t))
-            assert count == 1, "count evaluated too many times!"
-
-class OperatorPrecedenceGrammarTest4(ParseTestCase):
-    def runTest(self):
-
-        import pyparsing
-
-        word = pyparsing.Word(pyparsing.alphas)
-
-        def supLiteral(s):
-            """Returns the suppressed literal s"""
-            return pyparsing.Literal(s).suppress()
-
-        def booleanExpr(atom):
-            ops = [
-                (supLiteral(u"!"), 1, pyparsing.opAssoc.RIGHT, lambda s, l, t: ["!", t[0][0]]),
-                (pyparsing.oneOf(u"= !="), 2, pyparsing.opAssoc.LEFT, ),
-                (supLiteral(u"&"), 2, pyparsing.opAssoc.LEFT,  lambda s, l, t: ["&", t[0]]),
-                (supLiteral(u"|"), 2, pyparsing.opAssoc.LEFT,  lambda s, l, t: ["|", t[0]])]
-            return pyparsing.operatorPrecedence(atom, ops)
-
-        f = booleanExpr(word) + pyparsing.StringEnd()
-
-        tests = [
-            ("bar = foo", "[['bar', '=', 'foo']]"),
-            ("bar = foo & baz = fee", "['&', [['bar', '=', 'foo'], ['baz', '=', 'fee']]]"),
-            ]
-        for test,expected in tests:
-            print test
-            results = f.parseString(test)
-            print results
-            assert str(results) == expected, "failed to match expected results, got '%s'" % str(results)
-            print
-        
-
-class ParseResultsPickleTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import makeHTMLTags, ParseResults
-        import pickle
-        
-        body = makeHTMLTags("BODY")[0]
-        result = body.parseString("<BODY BGCOLOR='#00FFBB' FGCOLOR=black>")
-        print result.dump()
-        print
-
-        # TODO - add support for protocols >= 2
-        #~ for protocol in range(pickle.HIGHEST_PROTOCOL+1):
-        for protocol in range(2):
-            print "Test pickle dump protocol", protocol
-            try:
-                pickleString = pickle.dumps(result, protocol)
-            except Exception, e:
-                print "dumps exception:", e
-                newresult = ParseResults([])
-            else:
-                newresult = pickle.loads(pickleString)
-                print newresult.dump()
-                
-            assert result.dump() == newresult.dump(), "Error pickling ParseResults object (protocol=%d)" % protocol
-            print
-
-
-class ParseResultsWithNamedTupleTest(ParseTestCase):
-    def runTest(self):
-
-        from pyparsing import Literal,replaceWith
-
-        expr = Literal("A")
-        expr.setParseAction(replaceWith(tuple(["A","Z"])))
-        expr = expr.setResultsName("Achar")
-
-        res = expr.parseString("A")
-        print repr(res)
-        print res.Achar
-        assert res.Achar == ("A","Z"), "Failed accessing named results containing a tuple, got " + res.Achar
-
-
-class ParseHTMLTagsTest(ParseTestCase):
-    def runTest(self):
-        import pyparsing
-        test = """
-            <BODY>
-            <BODY BGCOLOR="#00FFCC">
-            <BODY BGCOLOR="#00FFAA"/>
-            <BODY BGCOLOR='#00FFBB' FGCOLOR=black>
-            <BODY/>
-            </BODY>
-        """
-        results = [ 
-            ("startBody", False, "", ""),
-            ("startBody", False, "#00FFCC", ""),
-            ("startBody", True,  "#00FFAA", ""),
-            ("startBody", False, "#00FFBB", "black"),
-            ("startBody", True, "", ""),
-            ("endBody", False, "", ""),
-            ]
-        
-        bodyStart, bodyEnd = pyparsing.makeHTMLTags("BODY")
-        resIter = iter(results)
-        for t,s,e in (bodyStart | bodyEnd).scanString( test ):
-            print test[s:e], "->", t.asList()
-            (expectedType, expectedEmpty, expectedBG, expectedFG) = resIter.next()
-            
-            tType = t.getName() 
-            #~ print tType,"==",expectedType,"?"
-            assert tType in "startBody endBody".split(), "parsed token of unknown type '%s'" % tType
-            assert tType == expectedType, "expected token of type %s, got %s" % (expectedType, tType) 
-            if tType == "startBody":
-                assert bool(t.empty) == expectedEmpty, "expected %s token, got %s" % ( expectedEmpty and "empty" or "not empty", 
-                                                                                                t.empty and "empty" or "not empty" )
-                assert t.bgcolor == expectedBG, "failed to match BGCOLOR, expected %s, got %s" % ( expectedBG, t.bgcolor )
-                assert t.fgcolor == expectedFG, "failed to match FGCOLOR, expected %s, got %s" % ( expectedFG, t.bgcolor )
-            elif tType == "endBody":
-                #~ print "end tag"
-                pass
-            else:
-                print "BAD!!!"
-
-class UpcaseDowncaseUnicode(ParseTestCase):
-    def runTest(self):
-    
-        import pyparsing as pp
-        import sys
-
-        a = u'\u00bfC\u00f3mo esta usted?'
-        ualphas = u"".join( [ unichr(i) for i in range(sys.maxunicode)
-                            if unichr(i).isalpha() ] )
-        uword = pp.Word(ualphas).setParseAction(pp.upcaseTokens)
-
-        print uword.searchString(a)
-
-        uword = pp.Word(ualphas).setParseAction(pp.downcaseTokens)
-
-        print uword.searchString(a)
-
-        if not IRON_PYTHON_ENV:
-            #test html data
-            html = "<TR class=maintxt bgColor=#ffffff> \
-                <TD vAlign=top>Производитель, модель</TD> \
-                <TD vAlign=top><STRONG>BenQ-Siemens CF61</STRONG></TD> \
-            ".decode('utf-8')
-
-            # u'Manufacturer, model
-            text_manuf = u'Производитель, модель'
-            manufacturer = pp.Literal(text_manuf)
-
-            td_start, td_end = pp.makeHTMLTags("td")
-            manuf_body =  td_start.suppress() + manufacturer + pp.SkipTo(td_end).setResultsName("cells", True) + td_end.suppress()
-
-            #~ manuf_body.setDebug()
-
-            for tokens in manuf_body.scanString(html):
-                print tokens
-
-class ParseUsingRegex(ParseTestCase):
-    def runTest(self):
-    
-        import re
-        import pyparsing
-        
-        signedInt = pyparsing.Regex(r'[-+][0-9]+')
-        unsignedInt = pyparsing.Regex(r'[0-9]+')
-        simpleString = pyparsing.Regex(r'("[^\"]*")|(\'[^\']*\')')
-        namedGrouping = pyparsing.Regex(r'("(?P<content>[^\"]*)")')
-        compiledRE = pyparsing.Regex(re.compile(r'[A-Z]+'))
-        
-        def testMatch (expression, instring, shouldPass, expectedString=None):
-            if shouldPass:
-                try:
-                    result = expression.parseString(instring)
-                    print '%s correctly matched %s' % (repr(expression), repr(instring))
-                    if expectedString != result[0]:
-                        print '\tbut failed to match the pattern as expected:'
-                        print '\tproduced %s instead of %s' % \
-                            (repr(result[0]), repr(expectedString))
-                    return True
-                except pyparsing.ParseException:
-                    print '%s incorrectly failed to match %s' % \
-                        (repr(expression), repr(instring))
-            else:
-                try:
-                    result = expression.parseString(instring)
-                    print '%s incorrectly matched %s' % (repr(expression), repr(instring))
-                    print '\tproduced %s as a result' % repr(result[0])
-                except pyparsing.ParseException:
-                    print '%s correctly failed to match %s' % \
-                        (repr(expression), repr(instring))
-                    return True
-            return False
-        
-        # These should fail
-        assert testMatch(signedInt, '1234 foo', False), "Re: (1) passed, expected fail"
-        assert testMatch(signedInt, '    +foo', False), "Re: (2) passed, expected fail"
-        assert testMatch(unsignedInt, 'abc', False), "Re: (3) passed, expected fail"
-        assert testMatch(unsignedInt, '+123 foo', False), "Re: (4) passed, expected fail"
-        assert testMatch(simpleString, 'foo', False), "Re: (5) passed, expected fail"
-        assert testMatch(simpleString, '"foo bar\'', False), "Re: (6) passed, expected fail"
-        assert testMatch(simpleString, '\'foo bar"', False), "Re: (7) passed, expected fail"
-
-        # These should pass
-        assert testMatch(signedInt, '   +123', True, '+123'), "Re: (8) failed, expected pass"
-        assert testMatch(signedInt, '+123', True, '+123'), "Re: (9) failed, expected pass"
-        assert testMatch(signedInt, '+123 foo', True, '+123'), "Re: (10) failed, expected pass"
-        assert testMatch(signedInt, '-0 foo', True, '-0'), "Re: (11) failed, expected pass"
-        assert testMatch(unsignedInt, '123 foo', True, '123'), "Re: (12) failed, expected pass"
-        assert testMatch(unsignedInt, '0 foo', True, '0'), "Re: (13) failed, expected pass"
-        assert testMatch(simpleString, '"foo"', True, '"foo"'), "Re: (14) failed, expected pass"
-        assert testMatch(simpleString, "'foo bar' baz", True, "'foo bar'"), "Re: (15) failed, expected pass"
-
-        assert testMatch(compiledRE, 'blah', False), "Re: (16) passed, expected fail"
-        assert testMatch(compiledRE, 'BLAH', True, 'BLAH'), "Re: (17) failed, expected pass"
-
-        assert testMatch(namedGrouping, '"foo bar" baz', True, '"foo bar"'), "Re: (16) failed, expected pass"
-        ret = namedGrouping.parseString('"zork" blah')
-        print ret.asList()
-        print ret.items()
-        print ret.content
-        assert ret.content == 'zork', "named group lookup failed"
-        assert ret[0] == simpleString.parseString('"zork" blah')[0], "Regex not properly returning ParseResults for named vs. unnamed groups"
-        
-        try:
-            #~ print "lets try an invalid RE"
-            invRe = pyparsing.Regex('("[^\"]*")|(\'[^\']*\'')
-        except Exception,e:
-            print "successfully rejected an invalid RE:",
-            print e
-        else:
-            assert False, "failed to reject invalid RE"
-            
-        invRe = pyparsing.Regex('')
-
-class CountedArrayTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word,nums,OneOrMore,countedArray
-        
-        testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3"
-
-        integer = Word(nums).setParseAction(lambda t: int(t[0]))
-        countedField = countedArray(integer)
-        
-        r = OneOrMore(countedField).parseString( testString )
-        print testString
-        print r.asList()
-        
-        assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \
-                "Failed matching countedArray, got " + str(r.asList())
-
-class CountedArrayTest2(ParseTestCase):
-    # addresses bug raised by Ralf Vosseler
-    def runTest(self):
-        from pyparsing import Word,nums,OneOrMore,countedArray
-        
-        testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3"
-
-        integer = Word(nums).setParseAction(lambda t: int(t[0]))
-        countedField = countedArray(integer)
-        
-        dummy = Word("A")
-        r = OneOrMore(dummy ^ countedField).parseString( testString )
-        print testString
-        print r.asList()
-        
-        assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \
-                "Failed matching countedArray, got " + str(r.asList())
-
-class LineAndStringEndTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import OneOrMore,lineEnd,alphanums,Word,stringEnd,delimitedList,SkipTo
-
-        les = OneOrMore(lineEnd)
-        bnf1 = delimitedList(Word(alphanums).leaveWhitespace(),les)
-        bnf2 = Word(alphanums) + stringEnd
-        bnf3 = Word(alphanums) + SkipTo(stringEnd)
-        tests = [
-            ("testA\ntestB\ntestC\n", ['testA', 'testB', 'testC']),
-            ("testD\ntestE\ntestF", ['testD', 'testE', 'testF']),
-            ("a", ['a']),
-             ]
-
-        for t in tests:
-            res1 = bnf1.parseString(t[0])
-            print res1,'=?',t[1]
-            assert res1.asList() == t[1], "Failed lineEnd/stringEnd test (1): "+repr(t[0])+ " -> "+str(res1.asList())
-            res2 = bnf2.searchString(t[0])
-            print res2[0].asList(),'=?',t[1][-1:]
-            assert res2[0].asList() == t[1][-1:], "Failed lineEnd/stringEnd test (2): "+repr(t[0])+ " -> "+str(res2[0].asList())
-            res3 = bnf3.parseString(t[0])
-            print repr(res3[1]),'=?',repr(t[0][len(res3[0])+1:])
-            assert res3[1] == t[0][len(res3[0])+1:], "Failed lineEnd/stringEnd test (3): " +repr(t[0])+ " -> "+str(res3[1].asList())
-
-        from pyparsing import Regex
-        import re
-
-        k = Regex(r'a+',flags=re.S+re.M)
-        k = k.parseWithTabs()
-        k = k.leaveWhitespace()
-        
-        tests = [
-            (r'aaa',['aaa']),
-            (r'\naaa',None),
-            (r'a\naa',None),
-            (r'aaa\n',None),
-            ]
-        for i,(src,expected) in enumerate(tests):
-            print i, repr(src).replace('\\\\','\\'),
-            try:
-                res = k.parseString(src, parseAll=True).asList()
-            except ParseException, pe:
-                res = None
-            print res
-            assert res == expected, "Failed on parseAll=True test %d" % i
-
-class VariableParseActionArgsTest(ParseTestCase):
-    def runTest(self):
-        
-        pa3 = lambda s,l,t: t
-        pa2 = lambda l,t: t
-        pa1 = lambda t: t
-        pa0 = lambda : None
-        class Callable3(object):
-            def __call__(self,s,l,t):
-                return t
-        class Callable2(object):
-            def __call__(self,l,t):
-                return t
-        class Callable1(object):
-            def __call__(self,t):
-                return t
-        class Callable0(object):
-            def __call__(self):
-                return 
-        class CallableS3(object):
-            #~ @staticmethod
-            def __call__(s,l,t):
-                return t
-            __call__=staticmethod(__call__)
-        class CallableS2(object):
-            #~ @staticmethod
-            def __call__(l,t):
-                return t
-            __call__=staticmethod(__call__)
-        class CallableS1(object):
-            #~ @staticmethod
-            def __call__(t):
-                return t
-            __call__=staticmethod(__call__)
-        class CallableS0(object):
-            #~ @staticmethod
-            def __call__():
-                return
-            __call__=staticmethod(__call__)
-        class CallableC3(object):
-            #~ @classmethod
-            def __call__(cls,s,l,t):
-                return t
-            __call__=classmethod(__call__)
-        class CallableC2(object):
-            #~ @classmethod
-            def __call__(cls,l,t):
-                return t
-            __call__=classmethod(__call__)
-        class CallableC1(object):
-            #~ @classmethod
-            def __call__(cls,t):
-                return t
-            __call__=classmethod(__call__)
-        class CallableC0(object):
-            #~ @classmethod
-            def __call__(cls):
-                return
-            __call__=classmethod(__call__)
-        
-        class parseActionHolder(object):
-            #~ @staticmethod
-            def pa3(s,l,t):
-                return t
-            pa3=staticmethod(pa3)
-            #~ @staticmethod
-            def pa2(l,t):
-                return t
-            pa2=staticmethod(pa2)
-            #~ @staticmethod
-            def pa1(t):
-                return t
-            pa1=staticmethod(pa1)
-            #~ @staticmethod
-            def pa0():
-                return
-            pa0=staticmethod(pa0)
-                
-        def paArgs(*args):
-            print args
-            return args[2]
-
-        class ClassAsPA0(object):
-            def __init__(self):
-                pass
-            def __str__(self):
-                return "A"
-                
-        class ClassAsPA1(object):
-            def __init__(self,t):
-                print "making a ClassAsPA1"
-                self.t = t
-            def __str__(self):
-                return self.t[0]
-                
-        class ClassAsPA2(object):
-            def __init__(self,l,t):
-                self.t = t
-            def __str__(self):
-                return self.t[0]
-                
-        class ClassAsPA3(object):
-            def __init__(self,s,l,t):
-                self.t = t
-            def __str__(self):
-                return self.t[0]
-                
-        class ClassAsPAStarNew(tuple):
-            def __new__(cls, *args):
-                print "make a ClassAsPAStarNew", args
-                return tuple.__new__(cls, *args[2].asList())
-            def __str__(self):
-                return ''.join(self)
-
-        #~ def ClassAsPANew(object):
-            #~ def __new__(cls, t):
-                #~ return object.__new__(cls, t)
-            #~ def __init__(self,t):
-                #~ self.t = t
-            #~ def __str__(self):
-                #~ return self.t
-
-        from pyparsing import Literal,OneOrMore
-        
-        A = Literal("A").setParseAction(pa0)
-        B = Literal("B").setParseAction(pa1)
-        C = Literal("C").setParseAction(pa2)
-        D = Literal("D").setParseAction(pa3)
-        E = Literal("E").setParseAction(Callable0())
-        F = Literal("F").setParseAction(Callable1())
-        G = Literal("G").setParseAction(Callable2())
-        H = Literal("H").setParseAction(Callable3())
-        I = Literal("I").setParseAction(CallableS0())
-        J = Literal("J").setParseAction(CallableS1())
-        K = Literal("K").setParseAction(CallableS2())
-        L = Literal("L").setParseAction(CallableS3())
-        M = Literal("M").setParseAction(CallableC0())
-        N = Literal("N").setParseAction(CallableC1())
-        O = Literal("O").setParseAction(CallableC2())
-        P = Literal("P").setParseAction(CallableC3())
-        Q = Literal("Q").setParseAction(paArgs)
-        R = Literal("R").setParseAction(parseActionHolder.pa3)
-        S = Literal("S").setParseAction(parseActionHolder.pa2)
-        T = Literal("T").setParseAction(parseActionHolder.pa1)
-        U = Literal("U").setParseAction(parseActionHolder.pa0)
-        V = Literal("V")
-        
-        gg = OneOrMore( A | C | D | E | F | G | H |
-                        I | J | K | L | M | N | O | P | Q | R | S | U | V | B | T)
-        testString = "VUTSRQPONMLKJIHGFEDCBA"
-        res = gg.parseString(testString)
-        print res.asList()
-        assert res.asList()==list(testString), "Failed to parse using variable length parse actions"
-        
-        A = Literal("A").setParseAction(ClassAsPA0)
-        B = Literal("B").setParseAction(ClassAsPA1)
-        C = Literal("C").setParseAction(ClassAsPA2)
-        D = Literal("D").setParseAction(ClassAsPA3)
-        E = Literal("E").setParseAction(ClassAsPAStarNew)
-        
-        gg = OneOrMore( A | B | C | D | E | F | G | H |
-                        I | J | K | L | M | N | O | P | Q | R | S | T | U | V)
-        testString = "VUTSRQPONMLKJIHGFEDCBA"
-        res = gg.parseString(testString)
-        print map(str,res)
-        assert map(str,res)==list(testString), "Failed to parse using variable length parse actions using class constructors as parse actions"
-        
-class EnablePackratParsing(ParseTestCase):
-    def runTest(self):
-        from pyparsing import ParserElement
-        ParserElement.enablePackrat()
-
-class SingleArgExceptionTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import ParseBaseException,ParseFatalException
-        
-        msg = ""
-        raisedMsg = ""
-        testMessage = "just one arg"
-        try:
-            raise ParseFatalException, testMessage
-        except ParseBaseException,pbe:
-            print "Received expected exception:", pbe
-            raisedMsg = pbe.msg
-        assert raisedMsg == testMessage, "Failed to get correct exception message"
-
-
-class KeepOriginalTextTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import makeHTMLTags, keepOriginalText
-        
-        def rfn(t):
-            return "%s:%d" % (t.src, len("".join(t)))
-
-        makeHTMLStartTag = lambda tag: makeHTMLTags(tag)[0].setParseAction(keepOriginalText)
-            
-        # use the lambda, Luke
-        #~ start, imge = makeHTMLTags('IMG')  
-        start = makeHTMLStartTag('IMG')
-
-        # don't replace our fancy parse action with rfn, 
-        # append rfn to the list of parse actions
-        #~ start.setParseAction(rfn)
-        start.addParseAction(rfn)
-
-        #start.setParseAction(lambda s,l,t:t.src)
-        text = '''_<img src="images/cal.png"
-            alt="cal image" width="16" height="15">_'''
-        s = start.transformString(text)
-        print s
-        assert s.startswith("_images/cal.png:"), "failed to preserve input s properly"
-        assert s.endswith("77_"),"failed to return full original text properly"
-
-class PackratParsingCacheCopyTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word,nums,ParserElement,delimitedList,Literal,Optional,alphas,alphanums,ZeroOrMore,empty
-
-        integer = Word(nums).setName("integer")
-        id = Word(alphas+'_',alphanums+'_')
-        simpleType = Literal('int');
-        arrayType= simpleType+ZeroOrMore('['+delimitedList(integer)+']')
-        varType = arrayType | simpleType
-        varDec  = varType + delimitedList(id + Optional('='+integer))+';'
-         
-        codeBlock = Literal('{}')
-         
-        funcDef = Optional(varType | 'void')+id+'('+(delimitedList(varType+id)|'void'|empty)+')'+codeBlock
-         
-        program = varDec | funcDef
-        input = 'int f(){}'
-        results = program.parseString(input)
-        print "Parsed '%s' as %s" % (input, results.asList())
-        assert results.asList() == ['int', 'f', '(', ')', '{}'], "Error in packrat parsing"
-
-class PackratParsingCacheCopyTest2(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Keyword,Word,Suppress,Forward,Optional,delimitedList,ParserElement,Group
-
-        DO,AA = map(Keyword, "DO AA".split())
-        LPAR,RPAR = map(Suppress,"()")
-        identifier = ~AA + Word("Z")
-
-        function_name = identifier.copy()
-        #~ function_name = ~AA + Word("Z")  #identifier.copy()
-        expr = Forward().setName("expr")
-        expr << (Group(function_name + LPAR + Optional(delimitedList(expr)) + RPAR).setName("functionCall") |
-                    identifier.setName("ident")#.setDebug()#.setBreak()
-                   )
-
-        stmt = DO + Group(delimitedList(identifier + ".*" | expr))
-        result = stmt.parseString("DO Z")
-        print result.asList()
-        assert len(result[1]) == 1, "packrat parsing is duplicating And term exprs"
-
-class ParseResultsDelTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import OneOrMore, Word, alphas, nums
-        
-        grammar = OneOrMore(Word(nums))("ints") + OneOrMore(Word(alphas))("words")
-        res = grammar.parseString("123 456 ABC DEF")
-        print res.dump()
-        origInts = res.ints.asList()
-        origWords = res.words.asList()
-        del res[1]
-        del res["words"]
-        print res.dump()
-        assert res[1]=='ABC',"failed to delete 0'th element correctly"
-        assert res.ints.asList()==origInts, "updated named attributes, should have updated list only"
-        assert res.words=="", "failed to update named attribute correctly"
-        assert res[-1]=='DEF', "updated list, should have updated named attributes only"
-        
-class WithAttributeParseActionTest(ParseTestCase):
-    def runTest(self):
-        """
-        This unit test checks withAttribute in these ways:
-        
-        * Argument forms as keywords and tuples
-        * Selecting matching tags by attribute
-        * Case-insensitive attribute matching
-        * Correctly matching tags having the attribute, and rejecting tags not having the attribute
-        
-        (Unit test written by voigts as part of the Google Highly Open Participation Contest)
-        """
-        
-        from pyparsing import makeHTMLTags, Word, withAttribute, nums
-        
-        data = """
-        <a>1</a>
-        <a b="x">2</a>
-        <a B="x">3</a>
-        <a b="X">4</a>
-        <a b="y">5</a>
-        """
-        tagStart, tagEnd = makeHTMLTags("a")
-        
-        expr = tagStart + Word(nums).setResultsName("value") + tagEnd
-          
-        expected = [['a', ['b', 'x'], False, '2', '</a>'], ['a', ['b', 'x'], False, '3', '</a>']]
-        
-        for attrib in [
-            withAttribute(b="x"),
-            #withAttribute(B="x"),
-            withAttribute(("b","x")),
-            #withAttribute(("B","x")),
-            ]:
-          
-          tagStart.setParseAction(attrib)
-          result = expr.searchString(data)
-          
-          print result.dump()
-          assert result.asList() == expected, "Failed test, expected %s, got %s" % (expected, result.asList())
-
-class NestedExpressionsTest(ParseTestCase):
-    def runTest(self):
-        """
-        This unit test checks nestedExpr in these ways:
-        - use of default arguments
-        - use of non-default arguments (such as a pyparsing-defined comment
-          expression in place of quotedString)
-        - use of a custom content expression
-        - use of a pyparsing expression for opener and closer is *OPTIONAL*
-        - use of input data containing nesting delimiters
-        - correct grouping of parsed tokens according to nesting of opening
-          and closing delimiters in the input string
-        
-        (Unit test written by christoph... as part of the Google Highly Open Participation Contest)
-        """
-        from pyparsing import nestedExpr, Literal, Regex, restOfLine, quotedString
-
-        #All defaults. Straight out of the example script. Also, qualifies for
-        #the bonus: note the fact that (Z | (E^F) & D) is not parsed :-).
-        # Tests for bug fixed in 1.4.10
-        print "Test defaults:"
-        teststring = "(( ax + by)*C) (Z | (E^F) & D)"
-
-        expr = nestedExpr()
-
-        expected = [[['ax', '+', 'by'], '*C']]
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected, "Defaults didn't work. That's a bad sign. Expected: %s, got: %s" % (expected, result)
-
-        #Going through non-defaults, one by one; trying to think of anything
-        #odd that might not be properly handled.
-
-        #Change opener
-        print "\nNon-default opener"
-        opener = "["
-        teststring = test_string = "[[ ax + by)*C)"
-        expected = [[['ax', '+', 'by'], '*C']]
-        expr = nestedExpr("[")
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected, "Non-default opener didn't work. Expected: %s, got: %s" % (expected, result)
-
-        #Change closer
-        print "\nNon-default closer"
-
-        teststring = test_string = "(( ax + by]*C]"
-        expected = [[['ax', '+', 'by'], '*C']]
-        expr = nestedExpr(closer="]")
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected, "Non-default closer didn't work. Expected: %s, got: %s" % (expected, result)
-
-        # #Multicharacter opener, closer
-        # opener = "bar"
-        # closer = "baz"
-        print "\nLiteral expressions for opener and closer"
-
-        opener,closer = map(Literal, "bar baz".split())
-        expr = nestedExpr(opener, closer, 
-                    content=Regex(r"([^b ]|b(?!a)|ba(?![rz]))+")) 
-                    
-        teststring = "barbar ax + bybaz*Cbaz"
-        expected = [[['ax', '+', 'by'], '*C']]
-        # expr = nestedExpr(opener, closer)
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected, "Multicharacter opener and closer didn't work. Expected: %s, got: %s" % (expected, result)
-
-        #Lisp-ish comments
-        print "\nUse ignore expression (1)"
-        comment = Regex(r";;.*")
-        teststring = \
-        """
-        (let ((greeting "Hello, world!")) ;;(foo bar
-           (display greeting))
-        """
-
-        expected = [['let', [['greeting', '"Hello,', 'world!"']], ';;(foo bar',\
-                         ['display', 'greeting']]]
-        expr = nestedExpr(ignoreExpr=comment)
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") didn't work. Expected: %s, got: %s" % (expected, result)
-
-
-        #Lisp-ish comments, using a standard bit of pyparsing, and an Or.
-        print "\nUse ignore expression (2)"
-        comment = ';;' + restOfLine 
-
-        teststring = \
-        """
-        (let ((greeting "Hello, )world!")) ;;(foo bar
-           (display greeting))
-        """
-
-        expected = [['let', [['greeting', '"Hello, )world!"']], ';;', '(foo bar', 
-                     ['display', 'greeting']]]
-        expr = nestedExpr(ignoreExpr=(comment ^ quotedString))
-        result = expr.parseString(teststring)
-        print result.dump()
-        assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") and quoted strings didn't work. Expected: %s, got: %s" % (expected, result)
-
-class ParseAllTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Word, cppStyleComment
-        
-        testExpr = Word("A")
-        
-        tests = [
-            ("AAAAA", False, True),
-            ("AAAAA", True, True),
-            ("AAABB", False, True),
-            ("AAABB", True, False),
-            ]
-        for s,parseAllFlag,shouldSucceed in tests:
-            try:
-                print "'%s' parseAll=%s (shouldSuceed=%s)" % (s, parseAllFlag, shouldSucceed)
-                testExpr.parseString(s,parseAllFlag)
-                assert shouldSucceed, "successfully parsed when should have failed"
-            except ParseException, pe:
-                assert not shouldSucceed, "failed to parse when should have succeeded"
-
-        # add test for trailing comments
-        testExpr.ignore(cppStyleComment)
-
-        tests = [
-            ("AAAAA //blah", False, True),
-            ("AAAAA //blah", True, True),
-            ("AAABB //blah", False, True),
-            ("AAABB //blah", True, False),
-            ]
-        for s,parseAllFlag,shouldSucceed in tests:
-            try:
-                print "'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)
-                testExpr.parseString(s,parseAllFlag)
-                assert shouldSucceed, "successfully parsed when should have failed"
-            except ParseException, pe:
-                assert not shouldSucceed, "failed to parse when should have succeeded"
-
-class GreedyQuotedStringsTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import QuotedString, sglQuotedString, dblQuotedString, quotedString, delimitedList
-        
-        src = """\
-           "string1", "strin""g2"
-           'string1', 'string2'
-           ^string1^, ^string2^
-           <string1>, <string2>"""
-        
-        testExprs = (sglQuotedString, dblQuotedString, quotedString, 
-                    QuotedString('"', escQuote='""'), QuotedString("'", escQuote="''"),
-                    QuotedString("^"), QuotedString("<",endQuoteChar=">"))
-        for expr in testExprs:
-            strs = delimitedList(expr).searchString(src)
-            print strs
-            assert bool(strs), "no matches found for test expression '%s'"  % expr
-            for lst in strs:
-                assert len(lst) == 2, "invalid match found for test expression '%s'"  % expr
-                
-        from pyparsing import alphas, nums, Word
-        src = """'ms1',1,0,'2009-12-22','2009-12-22 10:41:22') ON DUPLICATE KEY UPDATE sent_count = sent_count + 1, mtime = '2009-12-22 10:41:22';"""
-        tok_sql_quoted_value = (
-            QuotedString("'", "\\", "''", True, False) ^ 
-            QuotedString('"', "\\", '""', True, False))
-        tok_sql_computed_value = Word(nums)
-        tok_sql_identifier = Word(alphas)
-        
-        val = tok_sql_quoted_value | tok_sql_computed_value | tok_sql_identifier
-        vals = delimitedList(val)
-        print vals.parseString(src)
-        assert len(vals.parseString(src)) == 5, "error in greedy quote escaping"
-
-
-class WordBoundaryExpressionsTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import WordEnd, WordStart, oneOf
-
-        ws = WordStart()
-        we = WordEnd()
-        vowel = oneOf(list("AEIOUY"))
-        consonant = oneOf(list("BCDFGHJKLMNPQRSTVWXZ"))
-
-        leadingVowel = ws + vowel
-        trailingVowel = vowel + we
-        leadingConsonant = ws + consonant
-        trailingConsonant = consonant + we
-        internalVowel = ~ws + vowel + ~we
-
-        bnf = leadingVowel | trailingVowel
-
-        tests = """\
-        ABC DEF GHI
-          JKL MNO PQR
-        STU VWX YZ  """.splitlines()
-        tests.append( "\n".join(tests) )
-
-        expectedResult = [
-            [['D', 'G'], ['A'], ['C', 'F'], ['I'], ['E'], ['A', 'I']],
-            [['J', 'M', 'P'], [], ['L', 'R'], ['O'], [], ['O']],
-            [['S', 'V'], ['Y'], ['X', 'Z'], ['U'], [], ['U', 'Y']],
-            [['D', 'G', 'J', 'M', 'P', 'S', 'V'], 
-             ['A', 'Y'], 
-             ['C', 'F', 'L', 'R', 'X', 'Z'], 
-             ['I', 'O', 'U'], 
-             ['E'],
-             ['A', 'I', 'O', 'U', 'Y']],
-            ]
-            
-        for t,expected in zip(tests, expectedResult):
-            print t
-            results = map(lambda e: flatten(e.searchString(t).asList()), 
-                [
-                leadingConsonant,
-                leadingVowel,
-                trailingConsonant,
-                trailingVowel,
-                internalVowel,
-                bnf,
-                ]
-                )
-            print results
-            assert results==expected,"Failed WordBoundaryTest, expected %s, got %s" % (expected,results)
-            print
-
-class OptionalEachTest(ParseTestCase):
-    def runTest(self):
-        from pyparsing import Optional, Keyword
-        
-        the_input = "Major Tal Weiss"
-        parser1 = (Optional('Tal') + Optional('Weiss')) & Keyword('Major')
-        parser2 = Optional(Optional('Tal') + Optional('Weiss')) & Keyword('Major')
-        p1res = parser1.parseString( the_input)
-        p2res = parser2.parseString( the_input)
-        assert p1res.asList() == p2res.asList(), "Each failed to match with nested Optionals, " + \
-            str(p1res.asList()) + " should match " + str(p2res.asList())
-
-class SumParseResultsTest(ParseTestCase):
-    def runTest(self):
-
-        samplestr1 = "garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage"
-        samplestr2 = "garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage"
-        samplestr3 = "garbage;DOB 10-10-2010"
-        samplestr4 = "garbage;ID PARI12345678;more garbage- I am cool"
-
-        res1 = "ID:PARI12345678 DOB:10-10-2010 INFO:"
-        res2 = "ID:PARI12345678 DOB:10-10-2010 INFO:"
-        res3 = "ID: DOB:10-10-2010 INFO:"
-        res4 = "ID:PARI12345678 DOB: INFO: I am cool"
-
-        from pyparsing import Regex, Word, alphanums, restOfLine
-        dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob")
-        id_ref = "ID" + Word(alphanums,exact=12)("id")
-        info_ref = "-" + restOfLine("info")
-
-        person_data = dob_ref | id_ref | info_ref
-
-        tests = (samplestr1,samplestr2,samplestr3,samplestr4,)
-        results = (res1, res2, res3, res4,)
-        for test,expected in zip(tests, results):
-            person = sum(person_data.searchString(test))
-            result = "ID:%s DOB:%s INFO:%s" % (person.id, person.dob, person.info)
-            print test
-            print expected
-            print result
-            for pd in person_data.searchString(test):
-                print pd.dump()
-            print
-            assert expected == result, \
-                "Failed to parse '%s' correctly, \nexpected '%s', got '%s'" % (test,expected,result)
-
-class MiscellaneousParserTests(ParseTestCase):
-    def runTest(self):
-        import pyparsing
-        
-        runtests = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-        if IRON_PYTHON_ENV:
-            runtests = "ABCDEGHIJKLMNOPQRSTUVWXYZ"
-        
-        # test making oneOf with duplicate symbols
-        if "A" in runtests:
-            print "verify oneOf handles duplicate symbols"
-            try:
-                test1 = pyparsing.oneOf("a b c d a")
-            except RuntimeError:
-                assert False,"still have infinite loop in oneOf with duplicate symbols"
-        
-        # test MatchFirst bugfix
-        if "B" in runtests:
-            print "verify MatchFirst iterates properly"
-            results = pyparsing.quotedString.parseString("'this is a single quoted string'")
-            assert len(results) > 0, "MatchFirst error - not iterating over all choices"
-            
-        # verify streamline of subexpressions
-        if "C" in runtests:
-            print "verify proper streamline logic"
-            compound = pyparsing.Literal("A") + "B" + "C" + "D"
-            assert len(compound.exprs) == 2,"bad test setup"
-            print compound
-            compound.streamline()
-            print compound
-            assert len(compound.exprs) == 4,"streamline not working"
-        
-        # test for Optional with results name and no match
-        if "D" in runtests:
-            print "verify Optional's do not cause match failure if have results name"
-            testGrammar = pyparsing.Literal("A") + pyparsing.Optional("B").setResultsName("gotB") + pyparsing.Literal("C")
-            try:
-                testGrammar.parseString("ABC")
-                testGrammar.parseString("AC")
-            except pyparsing.ParseException, pe:
-                print pe.pstr,"->",pe
-                assert False, "error in Optional matching of string %s" % pe.pstr
-        
-        # test return of furthest exception
-        if "E" in runtests:
-            testGrammar = ( pyparsing.Literal("A") |
-                            ( pyparsing.Optional("B") + pyparsing.Literal("C") ) |
-                            pyparsing.Literal("D") )
-            try:
-                testGrammar.parseString("BC")
-                testGrammar.parseString("BD")
-            except pyparsing.ParseException, pe:
-                print pe.pstr,"->",pe
-                assert pe.pstr == "BD", "wrong test string failed to parse"
-                assert pe.loc == 1, "error in Optional matching, pe.loc="+str(pe.loc)
-
-        # test validate
-        if "F" in runtests:
-            print "verify behavior of validate()"
-            def testValidation( grmr, gnam, isValid ):
-                try:
-                    grmr.streamline()
-                    grmr.validate()
-                    assert isValid,"validate() accepted invalid grammar " + gnam
-                except pyparsing.RecursiveGrammarException,e:
-                    print grmr
-                    assert not isValid, "validate() rejected valid grammar " + gnam
-                
-            fwd = pyparsing.Forward()
-            g1 = pyparsing.OneOrMore( ( pyparsing.Literal("A") + "B" + "C" ) | fwd )
-            g2 = pyparsing.ZeroOrMore("C" + g1)
-            fwd << pyparsing.Group(g2)
-            testValidation( fwd, "fwd", isValid=True )
-                        
-            fwd2 = pyparsing.Forward()
-            fwd2 << pyparsing.Group("A" | fwd2)
-            testValidation( fwd2, "fwd2", isValid=False )
-                    
-            fwd3 = pyparsing.Forward()
-            fwd3 << pyparsing.Optional("A") + fwd3
-            testValidation( fwd3, "fwd3", isValid=False )
-
-        # test getName
-        if "G" in runtests:
-            print "verify behavior of getName()"
-            aaa = pyparsing.Group(pyparsing.Word("a")).setResultsName("A")
-            bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B")
-            ccc = pyparsing.Group(":" + pyparsing.Word("c")).setResultsName("C")
-            g1 = "XXX" + pyparsing.ZeroOrMore( aaa | bbb | ccc )
-            teststring = "XXX b b a b b a b :c b a"
-            names = []
-            print g1.parseString(teststring).dump()
-            for t in g1.parseString(teststring):
-                print t, repr(t)
-                try:
-                    names.append( t[0].getName() )
-                except:
-                    try:
-                        names.append( t.getName() )
-                    except:
-                        names.append( None )
-            print teststring
-            print names
-            assert names==[None, 'B', 'B', 'A', 'B', 'B', 'A', 'B', 'C', 'B', 'A'], \
-                "failure in getting names for tokens"
-
-        # test ParseResults.get() method
-        if "H" in runtests:
-            print "verify behavior of ParseResults.get()"
-            res = g1.parseString(teststring)
-            print res.get("A","A not found")[0]
-            print res.get("D","!D")
-            assert res.get("A","A not found")[0] == "a", "get on existing key failed"
-            assert res.get("D","!D") == "!D", "get on missing key failed"
-        
-        if "I" in runtests:
-            print "verify handling of Optional's beyond the end of string"
-            testGrammar = "A" + pyparsing.Optional("B") + pyparsing.Optional("C") + pyparsing.Optional("D")
-            testGrammar.parseString("A")
-            testGrammar.parseString("AB")
-        
-        # test creating Literal with empty string
-        if "J" in runtests:
-            print 'verify non-fatal usage of Literal("")'
-            e = pyparsing.Literal("")
-            try:
-                e.parseString("SLJFD")
-            except Exception,e:
-                assert False, "Failed to handle empty Literal"
-                
-        # test line() behavior when starting at 0 and the opening line is an \n
-        if "K" in runtests:
-            print 'verify correct line() behavior when first line is empty string'
-            assert pyparsing.line(0, "\nabc\ndef\n") == '', "Error in line() with empty first line in text"
-            txt = "\nabc\ndef\n"
-            results = [ pyparsing.line(i,txt) for i in range(len(txt)) ]
-            assert results == ['', 'abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], "Error in line() with empty first line in text"
-            txt = "abc\ndef\n"
-            results = [ pyparsing.line(i,txt) for i in range(len(txt)) ]
-            assert results == ['abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], "Error in line() with non-empty first line in text"
-
-        # test bugfix with repeated tokens when packrat parsing enabled
-        if "L" in runtests:
-            a = pyparsing.Literal("a")
-            b = pyparsing.Literal("b")
-            c = pyparsing.Literal("c")
-
-            abb = a + b + b
-            abc = a + b + c
-            aba = a + b + a
-            grammar = abb | abc | aba
-
-            assert ''.join(grammar.parseString( "aba" )) == 'aba', "Packrat ABA failure!"
-
-def makeTestSuite():
-    suite = TestSuite()
-    suite.addTest( PyparsingTestInit() )
-    suite.addTest( ParseIDLTest() )
-    suite.addTest( ParseASMLTest() )
-    suite.addTest( ParseFourFnTest() )
-    suite.addTest( ParseSQLTest() )
-    suite.addTest( ParseConfigFileTest() )
-    suite.addTest( ParseJSONDataTest() )
-    suite.addTest( ParseCommaSeparatedValuesTest() )
-    suite.addTest( ParseEBNFTest() )
-    suite.addTest( ScanStringTest() )
-    suite.addTest( QuotedStringsTest() )
-    suite.addTest( CustomQuotesTest() )
-    suite.addTest( CaselessOneOfTest() )
-    suite.addTest( AsXMLTest() )
-    suite.addTest( CommentParserTest() )
-    suite.addTest( ParseExpressionResultsTest() )
-    suite.addTest( ParseExpressionResultsAccumulateTest() )
-    suite.addTest( ReStringRangeTest() )
-    suite.addTest( ParseKeywordTest() )
-    suite.addTest( ParseHTMLTagsTest() )
-    suite.addTest( ParseUsingRegex() )
-    suite.addTest( SkipToParserTests() )
-    suite.addTest( CountedArrayTest() )
-    suite.addTest( CountedArrayTest2() )
-    suite.addTest( LineAndStringEndTest() )
-    suite.addTest( VariableParseActionArgsTest() )
-    suite.addTest( RepeaterTest() )
-    suite.addTest( RecursiveCombineTest() )
-    suite.addTest( OperatorPrecedenceGrammarTest1() )
-    suite.addTest( OperatorPrecedenceGrammarTest2() )
-    suite.addTest( OperatorPrecedenceGrammarTest3() )
-    suite.addTest( OperatorPrecedenceGrammarTest4() )
-    suite.addTest( ParseResultsPickleTest() )
-    suite.addTest( ParseResultsWithNamedTupleTest() )
-    suite.addTest( ParseResultsDelTest() )
-    suite.addTest( SingleArgExceptionTest() )
-    suite.addTest( UpcaseDowncaseUnicode() )
-    if not IRON_PYTHON_ENV:
-        suite.addTest( KeepOriginalTextTest() )
-    suite.addTest( PackratParsingCacheCopyTest() )
-    suite.addTest( PackratParsingCacheCopyTest2() )
-    suite.addTest( WithAttributeParseActionTest() )
-    suite.addTest( NestedExpressionsTest() )
-    suite.addTest( WordBoundaryExpressionsTest() )
-    suite.addTest( ParseAllTest() )
-    suite.addTest( GreedyQuotedStringsTest() )
-    suite.addTest( OptionalEachTest() )
-    suite.addTest( SumParseResultsTest() )
-    suite.addTest( MiscellaneousParserTests() )
-    if TEST_USING_PACKRAT:
-        # retest using packrat parsing (disable those tests that aren't compatible)
-        suite.addTest( EnablePackratParsing() )
-        
-        unpackrattables = [ EnablePackratParsing, RepeaterTest, ]
-        
-        # add tests to test suite a second time, to run with packrat parsing
-        # (leaving out those that we know wont work with packrat)
-        packratTests = [t.__class__() for t in suite._tests
-                            if t.__class__ not in unpackrattables]
-        suite.addTests( packratTests )
-        
-    return suite
-    
-def makeTestSuiteTemp():
-    suite = TestSuite()
-    suite.addTest( PyparsingTestInit() )
-    suite.addTest( OptionalEachTest() )
-        
-    return suite
-
-console = False
-console = True
-
-#~ from line_profiler import LineProfiler
-#~ from pyparsing import ParseResults
-#~ lp = LineProfiler(ParseResults.__setitem__)
-
-if console:
-    #~ # console mode
-    testRunner = TextTestRunner()
-    testRunner.run( makeTestSuite() )
-    #~ testRunner.run( makeTestSuiteTemp() )
-    #~ lp.run("testRunner.run( makeTestSuite() )")
-else:
-    # HTML mode
-    outfile = "testResults.html"
-    outstream = file(outfile,"w")
-    testRunner = HTMLTestRunner.HTMLTestRunner( stream=outstream )
-    testRunner.run( makeTestSuite() )
-    outstream.close()
-
-    import os
-    os.system(r'"C:\Program Files\Internet Explorer\iexplore.exe" file://' + outfile)
-
-#~ lp.print_stats()
\ No newline at end of file
diff --git a/unitTests.py b/unitTests.py
new file mode 100644
--- /dev/null
+++ b/unitTests.py
@@ -0,0 +1,2117 @@
+# -*- coding: UTF-8 -*-
+from unittest import TestCase, TestSuite, TextTestRunner
+from pyparsing import ParseException
+import HTMLTestRunner
+
+import sys
+import pprint
+import pdb
+
+TEST_USING_PACKRAT = True
+#~ TEST_USING_PACKRAT = False
+
+# simple utility for flattening nested lists
+def flatten(L):
+    if type(L) is not list: return [L]
+    if L == []: return L
+    return flatten(L[0]) + flatten(L[1:])
+
+"""
+class ParseTest(TestCase):
+    def setUp(self):
+        pass
+        
+    def runTest(self):
+        assert 1==1, "we've got bigger problems..."
+        
+    def tearDown(self):
+        pass
+"""
+
+class ParseTestCase(TestCase):
+    def setUp(self):
+        print ">>>> Starting test",str(self)
+    
+    def runTest(self):
+        pass
+        
+    def tearDown(self):
+        print "<<<< End of test",str(self)
+        print  
+        
+    def __str__(self):
+        return self.__class__.__name__
+        
+class PyparsingTestInit(ParseTestCase):
+    def setUp(self):
+        from pyparsing import __version__ as pyparsingVersion
+        print "Beginning test of pyparsing, version", pyparsingVersion
+        print "Python version", sys.version
+    def tearDown(self):
+        pass
+        
+class ParseASMLTest(ParseTestCase):
+    def runTest(self):
+        import parseASML
+        files = [ ("A52759.txt", 2150, True, True, 0.38, 25, "21:47:17", "22:07:32", 235),
+                  ("24141506_P5107RM59_399A1457N1_PHS04", 373,True, True, 0.5, 1, "11:35:25", "11:37:05", 183),
+                  ("24141506_P5107RM59_399A1457N1_PHS04B", 373, True, True, 0.5, 1, "01:02:54", "01:04:49", 186),
+                  ("24157800_P5107RM74_399A1828M1_PHS04", 1141, True, False, 0.5, 13, "00:00:54", "23:59:48", 154) ]
+        for testFile,numToks,trkInpUsed,trkOutpUsed,maxDelta,numWafers,minProcBeg,maxProcEnd,maxLevStatsIV in files:
+            print "Parsing",testFile,"...",
+            #~ text = "\n".join( [ line for line in file(testFile) ] )
+            #~ results = parseASML.BNF().parseString( text )
+            results = parseASML.BNF().parseFile( testFile )
+            #~ pprint.pprint( results.asList() )
+            #~ pprint.pprint( results.batchData.asList() )
+            #~ print results.batchData.keys()
+                    
+            allToks = flatten( results.asList() )
+            assert len(allToks) == numToks, \
+                "wrong number of tokens parsed (%s), got %d, expected %d" % (testFile, len(allToks),numToks)
+            assert results.batchData.trackInputUsed == trkInpUsed, "error evaluating results.batchData.trackInputUsed"
+            assert results.batchData.trackOutputUsed == trkOutpUsed, "error evaluating results.batchData.trackOutputUsed"
+            assert results.batchData.maxDelta == maxDelta,"error evaluating results.batchData.maxDelta"
+            assert len(results.waferData) == numWafers, "did not read correct number of wafers"
+            assert min([wd.procBegin for wd in results.waferData]) == minProcBeg, "error reading waferData.procBegin"
+            assert max([results.waferData[k].procEnd for k in range(len(results.waferData))]) == maxProcEnd, "error reading waferData.procEnd"
+            assert sum(results.levelStatsIV['MAX']) == maxLevStatsIV, "error reading levelStatsIV"
+            assert sum(results.levelStatsIV.MAX) == maxLevStatsIV, "error reading levelStatsIV"
+            print "OK"
+            print testFile,len(allToks)
+            #~ print "results.batchData.trackInputUsed =",results.batchData.trackInputUsed
+            #~ print "results.batchData.trackOutputUsed =",results.batchData.trackOutputUsed
+            #~ print "results.batchData.maxDelta =",results.batchData.maxDelta
+            #~ print len(results.waferData)," wafers"
+            #~ print min([wd.procBegin for wd in results.waferData])
+            #~ print max([results.waferData[k].procEnd for k in range(len(results.waferData))])
+            #~ print sum(results.levelStatsIV['MAX.'])
+        
+
+class ParseFourFnTest(ParseTestCase):
+    def runTest(self):
+        import fourFn
+        def test(s,ans):
+            fourFn.exprStack = []
+            results = fourFn.BNF().parseString( s )
+            resultValue = fourFn.evaluateStack( fourFn.exprStack )
+            assert resultValue == ans, "failed to evaluate %s, got %f" % ( s, resultValue )
+            print s, "->", resultValue
+            
+        test( "9", 9 )
+        test( "9 + 3 + 6", 18 )
+        test( "9 + 3 / 11", 9.0+3.0/11.0)
+        test( "(9 + 3)", 12 )
+        test( "(9+3) / 11", (9.0+3.0)/11.0 )
+        test( "9 - (12 - 6)", 3)
+        test( "2*3.14159", 6.28318)
+        test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535/10.0 )
+        test( "PI * PI / 10", 3.1415926535*3.1415926535/10.0 )
+        test( "PI*PI/10", 3.1415926535*3.1415926535/10.0 )
+        test( "6.02E23 * 8.048", 6.02E23 * 8.048 )
+        test( "e / 3", 2.718281828/3.0 )
+        test( "sin(PI/2)", 1.0 )
+        test( "trunc(E)", 2.0 )
+        test( "E^PI", 2.718281828**3.1415926535 )
+        test( "2^3^2", 2**3**2)
+        test( "2^3+2", 2**3+2)
+        test( "2^9", 2**9 )
+        test( "sgn(-2)", -1 )
+        test( "sgn(0)", 0 )
+        test( "sgn(0.1)", 1 )
+
+class ParseSQLTest(ParseTestCase):
+    def runTest(self):
+        import simpleSQL
+        
+        def test(s, numToks, errloc=-1 ):
+            try:
+                sqlToks = flatten( simpleSQL.simpleSQL.parseString(s).asList() )
+                print s,sqlToks,len(sqlToks)
+                assert len(sqlToks) == numToks
+            except ParseException, e:
+                if errloc >= 0:
+                    assert e.loc == errloc
+                    
+            
+        test( "SELECT * from XYZZY, ABC", 6 )
+        test( "select * from SYS.XYZZY", 5 )
+        test( "Select A from Sys.dual", 5 )
+        test( "Select A,B,C from Sys.dual", 7 )
+        test( "Select A, B, C from Sys.dual", 7 )
+        test( "Select A, B, C from Sys.dual, Table2   ", 8 )
+        test( "Xelect A, B, C from Sys.dual", 0, 0 )
+        test( "Select A, B, C frox Sys.dual", 0, 15 )
+        test( "Select", 0, 6 )
+        test( "Select &&& frox Sys.dual", 0, 7 )
+        test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE')", 12 )
+        test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)", 20 )
+        test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators", 10 )
+
+class ParseConfigFileTest(ParseTestCase):
+    def runTest(self):
+        import configParse
+        
+        def test(fnam,numToks,resCheckList):
+            print "Parsing",fnam,"...",
+            iniFileLines = "\n".join([ lin for lin in file(fnam) ])
+            iniData = configParse.inifile_BNF().parseString( iniFileLines )
+            print len(flatten(iniData.asList()))
+            #~ pprint.pprint( iniData.asList() )
+            #~ pprint.pprint( repr(iniData) )
+            #~ print len(iniData), len(flatten(iniData.asList()))
+            print iniData.keys()
+            #~ print iniData.users.keys()
+            #~ print
+            assert len(flatten(iniData.asList())) == numToks, "file %s not parsed correctly" % fnam
+            for chk in resCheckList:
+                print chk[0], eval("iniData."+chk[0]), chk[1]
+                assert eval("iniData."+chk[0]) == chk[1]
+            print "OK"
+            
+        test("karthik.ini", 23, 
+                [ ("users.K","8"), 
+                  ("users.mod_scheme","'QPSK'"),
+                  ("users.Na", "K+2") ]
+                  )
+        test("setup.ini", 125, 
+                [ ("Startup.audioinf", "M3i"),
+                  ("Languages.key1", "0x0003"),
+                  ("test.foo","bar") ] )
+
+class ParseJSONDataTest(ParseTestCase):
+    def runTest(self):
+        from jsonParser import jsonObject
+        from jsonParserFull import test1,test2,test3,test4,test5
+        
+        expected = [
+            [],
+            [],
+            [],
+            [],
+            [],
+            ]
+            
+        import pprint
+        for t,exp in zip((test1,test2,test3,test4,test5),expected):
+            result = jsonObject.parseString(t)
+##            print result.dump()
+            pprint.pprint(result.asList())
+            print
+##            if result.asList() != exp:
+##                print "Expected %s, parsed results as %s" % (exp, result.asList())
+
+class ParseCommaSeparatedValuesTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import commaSeparatedList
+        import string
+        
+        testData = [
+            "a,b,c,100.2,,3",
+            "d, e, j k , m  ",
+            "'Hello, World', f, g , , 5.1,x",
+            "John Doe, 123 Main St., Cleveland, Ohio",
+            "Jane Doe, 456 St. James St., Los Angeles , California   ",
+            "",
+            ]
+        testVals = [
+            [ (3,'100.2'), (4,''), (5, '3') ],
+            [ (2, 'j k'), (3, 'm') ],
+            [ (0, "'Hello, World'"), (2, 'g'), (3, '') ],
+            [ (0,'John Doe'), (1, '123 Main St.'), (2, 'Cleveland'), (3, 'Ohio') ], 
+            [ (0,'Jane Doe'), (1, '456 St. James St.'), (2, 'Los Angeles'), (3, 'California') ]
+            ]
+        for line,tests in zip(testData, testVals):
+            print "Parsing: \""+line+"\" ->",
+            results = commaSeparatedList.parseString(line)
+            print results.asList()
+            for t in tests:
+                if not(len(results)>t[0] and results[t[0]] == t[1]):
+                    print "$$$", results.dump()
+                    print "$$$", results[0]
+                assert len(results)>t[0] and results[t[0]] == t[1],"failed on %s, item %d s/b '%s', got '%s'" % ( line, t[0], t[1], str(results.asList()) )
+
+class ParseEBNFTest(ParseTestCase):
+    def runTest(self):
+        import ebnf
+        from pyparsing import Word, quotedString, alphas, nums,ParserElement
+        
+        print 'Constructing EBNF parser with pyparsing...'
+        
+        grammar = '''
+        syntax = (syntax_rule), {(syntax_rule)};
+        syntax_rule = meta_identifier, '=', definitions_list, ';';
+        definitions_list = single_definition, {'|', single_definition};
+        single_definition = syntactic_term, {',', syntactic_term};
+        syntactic_term = syntactic_factor,['-', syntactic_factor];
+        syntactic_factor = [integer, '*'], syntactic_primary;
+        syntactic_primary = optional_sequence | repeated_sequence |
+          grouped_sequence | meta_identifier | terminal_string;
+        optional_sequence = '[', definitions_list, ']';
+        repeated_sequence = '{', definitions_list, '}';
+        grouped_sequence = '(', definitions_list, ')';
+        (* 
+        terminal_string = "'", character - "'", {character - "'"}, "'" |
+          '"', character - '"', {character - '"'}, '"';
+         meta_identifier = letter, {letter | digit};
+        integer = digit, {digit}; 
+        *)
+        '''
+        
+        table = {}
+        table['terminal_string'] = quotedString
+        table['meta_identifier'] = Word(alphas+"_", alphas+"_"+nums)
+        table['integer'] = Word(nums)
+        
+        print 'Parsing EBNF grammar with EBNF parser...'
+        parsers = ebnf.parse(grammar, table)
+        ebnf_parser = parsers['syntax']
+        #~ print ",\n ".join( str(parsers.keys()).split(", ") )
+        print "-","\n- ".join( parsers.keys() )
+        assert len(parsers.keys()) == 13, "failed to construct syntax grammar"
+
+        print 'Parsing EBNF grammar with generated EBNF parser...'
+        parsed_chars = ebnf_parser.parseString(grammar)
+        parsed_char_len = len(parsed_chars)
+        
+        print "],\n".join(str( parsed_chars.asList() ).split("],"))
+        assert len(flatten(parsed_chars.asList())) == 98, "failed to tokenize grammar correctly"
+        
+
+class ParseIDLTest(ParseTestCase):
+    def runTest(self):
+        import idlParse
+
+        def test( strng, numToks, errloc=0 ):
+            print strng
+            try:
+                bnf = idlParse.CORBA_IDL_BNF()
+                tokens = bnf.parseString( strng )
+                print "tokens = "
+                pprint.pprint( tokens.asList() )
+                tokens = flatten( tokens.asList() )
+                print len(tokens)
+                assert len(tokens) == numToks, "error matching IDL string, %s -> %s" % (strng, str(tokens) )
+            except ParseException, err:
+                print err.line
+                print " "*(err.column-1) + "^"
+                print err
+                assert numToks == 0, "unexpected ParseException while parsing %s, %s" % (strng, str(err) )
+                assert err.loc == errloc, "expected ParseException at %d, found exception at %d" % (errloc, err.loc)
+            
+        test(
+            """
+            /*
+             * a block comment *
+             */
+            typedef string[10] tenStrings;
+            typedef sequence<string> stringSeq;
+            typedef sequence< sequence<string> > stringSeqSeq;
+            
+            interface QoSAdmin {
+                stringSeq method1( in string arg1, inout long arg2 );
+                stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
+                string method3();
+              };
+            """, 59
+            )
+        test(
+            """
+            /*
+             * a block comment *
+             */
+            typedef string[10] tenStrings;
+            typedef 
+                /** ** *** **** *
+                 * a block comment *
+                 */
+                sequence<string> /*comment inside an And */ stringSeq;
+            /* */  /**/ /***/ /****/
+            typedef sequence< sequence<string> > stringSeqSeq;
+            
+            interface QoSAdmin {
+                stringSeq method1( in string arg1, inout long arg2 );
+                stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
+                string method3();
+              };
+            """, 59
+            )
+        test(
+            r"""
+              const string test="Test String\n";
+              const long  a = 0;
+              const long  b = -100;
+              const float c = 3.14159;
+              const long  d = 0x007f7f7f;
+              exception TestException
+                {
+                string msg;
+                sequence<string> dataStrings;
+                };
+              
+              interface TestInterface
+                {
+                void method1( in string arg1, inout long arg2 );
+                };
+            """, 60
+            )
+        test(
+            """
+            module Test1 
+              {
+              exception TestException
+                {
+                string msg;
+                ];
+              
+              interface TestInterface
+                {
+                void method1( in string arg1, inout long arg2 ) 
+                  raises ( TestException );
+                };
+              };
+            """, 0, 57
+            )
+        test(
+            """
+            module Test1 
+              {
+              exception TestException
+                {
+                string msg;
+                };
+        
+              };
+            """, 13
+            )
+    
+class ParseVerilogTest(ParseTestCase):
+    def runTest(self):
+        pass
+
+class RunExamplesTest(ParseTestCase):
+    def runTest(self):
+        pass
+        
+class ScanStringTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word, Combine, Suppress, CharsNotIn, nums, StringEnd
+        testdata = """
+            <table border="0" cellpadding="3" cellspacing="3" frame="" width="90%">
+                <tr align="left" valign="top">
+                        <td><b>Name</b></td>
+                        <td><b>IP Address</b></td>
+                        <td><b>Location</b></td>
+                </tr>
+                <tr align="left" valign="top" bgcolor="#c7efce">
+                        <td>time-a.nist.gov</td>
+                        <td>129.6.15.28</td>
+                        <td>NIST, Gaithersburg, Maryland</td>
+                </tr>
+                <tr align="left" valign="top">
+                        <td>time-b.nist.gov</td>
+                        <td>129.6.15.29</td>
+                        <td>NIST, Gaithersburg, Maryland</td>
+                </tr>
+                <tr align="left" valign="top" bgcolor="#c7efce">
+                        <td>time-a.timefreq.bldrdoc.gov</td>
+                        <td>132.163.4.101</td>
+                        <td>NIST, Boulder, Colorado</td>
+                </tr>
+                <tr align="left" valign="top">
+                        <td>time-b.timefreq.bldrdoc.gov</td>
+                        <td>132.163.4.102</td>
+                        <td>NIST, Boulder, Colorado</td>
+                </tr>
+                <tr align="left" valign="top" bgcolor="#c7efce">
+                        <td>time-c.timefreq.bldrdoc.gov</td>
+                        <td>132.163.4.103</td>
+                        <td>NIST, Boulder, Colorado</td>
+                </tr>
+            </table>
+            """
+        integer = Word(nums)
+        ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer )
+        tdStart = Suppress("<td>")
+        tdEnd = Suppress("</td>")
+        timeServerPattern =  tdStart + ipAddress.setResultsName("ipAddr") + tdEnd + \
+                tdStart + CharsNotIn("<").setResultsName("loc") + tdEnd
+        servers = \
+            [ srvr.ipAddr for srvr,startloc,endloc in timeServerPattern.scanString( testdata ) ]
+            
+        print servers
+        assert servers == ['129.6.15.28', '129.6.15.29', '132.163.4.101', '132.163.4.102', '132.163.4.103'], \
+            "failed scanString()"
+        
+        # test for stringEnd detection in scanString
+        foundStringEnds = [ r for r in StringEnd().scanString("xyzzy") ]
+        print foundStringEnds
+        assert foundStringEnds, "Failed to find StringEnd in scanString"
+            
+class QuotedStringsTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import sglQuotedString,dblQuotedString,quotedString
+        testData = \
+            """
+                'a valid single quoted string'
+                'an invalid single quoted string
+                 because it spans lines'
+                "a valid double quoted string"
+                "an invalid double quoted string
+                 because it spans lines"
+            """
+        print testData
+        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(testData) ]
+        print sglStrings
+        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==47), \
+            "single quoted string failure"
+        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(testData) ]
+        print dblStrings
+        assert len(dblStrings) == 1 and (dblStrings[0][1]==154 and dblStrings[0][2]==184), \
+            "double quoted string failure"
+        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(testData) ]
+        print allStrings
+        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==47) and \
+                                         (allStrings[1][1]==154 and allStrings[1][2]==184), \
+            "quoted string failure"
+        
+        escapedQuoteTest = \
+            r"""
+                'This string has an escaped (\') quote character'
+                "This string has an escaped (\") quote character"
+            """
+        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(escapedQuoteTest) ]
+        print sglStrings
+        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \
+            "single quoted string escaped quote failure (%s)" % str(sglStrings[0])
+        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(escapedQuoteTest) ]
+        print dblStrings
+        assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \
+            "double quoted string escaped quote failure (%s)" % str(dblStrings[0])
+        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(escapedQuoteTest) ]
+        print allStrings
+        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and
+                                          allStrings[1][1]==83 and allStrings[1][2]==132), \
+            "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])
+        
+        dblQuoteTest = \
+            r"""
+                'This string has an doubled ('') quote character'
+                "This string has an doubled ("") quote character"
+            """
+        sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(dblQuoteTest) ]
+        print sglStrings
+        assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \
+            "single quoted string escaped quote failure (%s)" % str(sglStrings[0])
+        dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(dblQuoteTest) ]
+        print dblStrings
+        assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \
+            "double quoted string escaped quote failure (%s)" % str(dblStrings[0])
+        allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(dblQuoteTest) ]
+        print allStrings
+        assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and
+                                          allStrings[1][1]==83 and allStrings[1][2]==132), \
+            "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])
+        
+class CaselessOneOfTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import oneOf,ZeroOrMore
+        
+        caseless1 = oneOf("d a b c aA B A C", caseless=True)
+        caseless1str = str( caseless1 )
+        print caseless1str
+        caseless2 = oneOf("d a b c Aa B A C", caseless=True)
+        caseless2str = str( caseless2 )
+        print caseless2str
+        assert caseless1str.upper() == caseless2str.upper(), "oneOf not handling caseless option properly"
+        assert caseless1str != caseless2str, "Caseless option properly sorted"
+        
+        res = ZeroOrMore(caseless1).parseString("AAaaAaaA")
+        print res
+        assert len(res) == 4, "caseless1 oneOf failed"
+        assert "".join(res) == "aA"*4,"caseless1 CaselessLiteral return failed"
+        
+        res = ZeroOrMore(caseless2).parseString("AAaaAaaA")
+        print res
+        assert len(res) == 4, "caseless2 oneOf failed"
+        assert "".join(res) == "Aa"*4,"caseless1 CaselessLiteral return failed"
+        
+
+class AsXMLTest(ParseTestCase):
+    def runTest(self):
+        
+        import pyparsing
+        # test asXML()
+        
+        aaa = pyparsing.Word("a").setResultsName("A")
+        bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B")
+        ccc = pyparsing.Combine(":" + pyparsing.Word("c")).setResultsName("C")
+        g1 = "XXX>&<" + pyparsing.ZeroOrMore( aaa | bbb | ccc )
+        teststring = "XXX>&< b b a b b a b :c b a"
+        #~ print teststring
+        print "test including all items"
+        xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=False)
+        assert xml=="\n".join(["",
+                                "<TEST>",
+                                "  <ITEM>XXX&gt;&amp;&lt;</ITEM>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <C>:c</C>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "</TEST>",
+                                ] ), \
+            "failed to generate XML correctly showing all items: \n[" + xml + "]"
+        print "test filtering unnamed items"
+        xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=True)
+        assert xml=="\n".join(["",
+                                "<TEST>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <C>:c</C>",
+                                "  <B>",
+                                "    <ITEM>b</ITEM>",
+                                "  </B>",
+                                "  <A>a</A>",
+                                "</TEST>", 
+                                ] ), \
+            "failed to generate XML correctly, filtering unnamed items: " + xml
+
+class AsXMLTest2(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Suppress,Optional,CharsNotIn,Combine,ZeroOrMore,Word,Group
+        
+        EndOfLine = Word("\n").setParseAction(lambda s,l,t: [' '])
+        whiteSpace=Word('\t ')
+        Mexpr = Suppress(Optional(whiteSpace)) + CharsNotIn('\\"\t \n') + Optional(" ") + \
+                Suppress(Optional(whiteSpace))
+        reducedString = Combine(Mexpr + ZeroOrMore(EndOfLine + Mexpr))
+        
+        QuotedReducedString = Combine( Suppress(_dblQuote) + ZeroOrMore( reducedString |
+                                                                         _escapedChar ) + \
+                                       Suppress(_dblQuote )).streamline()
+        
+        Manifest_string = QuotedReducedString.setResultsName('manifest_string')
+        
+        Identifier  = Word( alphas, alphanums+ '_$' ).setResultsName("identifier")
+        Index_string = CharsNotIn('\\";\n')
+        Index_string.setName('index_string')
+        Index_term_list = (
+                Group(delimitedList(Manifest_string, delim=',')) | \
+                Index_string
+                ).setResultsName('value')
+        
+        IndexKey = Identifier.setResultsName('key')
+        IndexKey.setName('key')
+        Index_clause = Group(IndexKey + Suppress(':') + Optional(Index_term_list))
+        Index_clause.setName('index_clause')
+        Index_list = Index_clause.setResultsName('index') 
+        Index_list.setName('index_list')
+        Index_block = Group('indexing' + Group(OneOrMore(Index_list + Suppress(';')))).setResultsName('indexes')
+        
+
+class CommentParserTest(ParseTestCase):
+    def runTest(self):
+        import pyparsing
+        print "verify processing of C and HTML comments"
+        testdata = """
+        /* */
+        /** **/
+        /**/
+        /***/
+        /****/
+        /* /*/
+        /** /*/
+        /*** /*/
+        /* 
+         ablsjdflj
+         */
+        """
+        foundLines = [ pyparsing.lineno(s,testdata)
+            for t,s,e in pyparsing.cStyleComment.scanString(testdata) ]
+        assert foundLines == range(11)[2:],"only found C comments on lines "+str(foundLines)
+        testdata = """
+        <!-- -->
+        <!--- --->
+        <!---->
+        <!----->
+        <!------>
+        <!-- /-->
+        <!--- /-->
+        <!---- /-->
+        <!---- /- ->
+        <!---- / -- >
+        <!-- 
+         ablsjdflj
+         -->
+        """
+        foundLines = [ pyparsing.lineno(s,testdata)
+            for t,s,e in pyparsing.htmlComment.scanString(testdata) ]
+        assert foundLines == range(11)[2:],"only found HTML comments on lines "+str(foundLines)
+
+        # test C++ single line comments that have line terminated with '\' (should continue comment to following line)
+        testSource = r"""
+            // comment1
+            // comment2 \
+            still comment 2
+            // comment 3
+            """
+        assert len(pyparsing.cppStyleComment.searchString(testSource)[1][0]) == 41, r"failed to match single-line comment with '\' at EOL"
+
+class ParseExpressionResultsTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word,alphas,OneOrMore,Optional,Group
+
+        a = Word("a",alphas).setName("A")
+        b = Word("b",alphas).setName("B")
+        c = Word("c",alphas).setName("C")
+        ab = (a + b).setName("AB")
+        abc = (ab + c).setName("ABC")
+        word = Word(alphas).setName("word")
+        
+        #~ words = OneOrMore(word).setName("words")
+        words = Group(OneOrMore(~a + word)).setName("words")
+        
+        #~ phrase = words.setResultsName("Head") + \
+                    #~ ( abc ^ ab ^ a ).setResultsName("ABC") + \
+                    #~ words.setResultsName("Tail")
+        #~ phrase = words.setResultsName("Head") + \
+                    #~ ( abc | ab | a ).setResultsName("ABC") + \
+                    #~ words.setResultsName("Tail")
+        phrase = words.setResultsName("Head") + \
+                    Group( a + Optional(b + Optional(c)) ).setResultsName("ABC") + \
+                    words.setResultsName("Tail")
+        
+        results = phrase.parseString("xavier yeti alpha beta charlie will beaver")
+        print results,results.Head, results.ABC,results.Tail
+        for key,ln in [("Head",2), ("ABC",3), ("Tail",2)]:
+            #~ assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key].asList()))
+            assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key]))
+        
+
+class ParseKeywordTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Literal,Keyword
+        
+        kw = Keyword("if")
+        lit = Literal("if")
+        
+        def test(s,litShouldPass,kwShouldPass):
+            print "Test",s
+            print "Match Literal",
+            try:
+                print lit.parseString(s)
+            except:
+                print "failed"
+                if litShouldPass: assert False, "Literal failed to match %s, should have" % s
+            else:
+                if not litShouldPass: assert False, "Literal matched %s, should not have" % s
+        
+            print "Match Keyword",
+            try:
+                print kw.parseString(s)
+            except:
+                print "failed"
+                if kwShouldPass: assert False, "Keyword failed to match %s, should have" % s
+            else:
+                if not kwShouldPass: assert False, "Keyword matched %s, should not have" % s
+        
+        test("ifOnlyIfOnly", True, False)
+        test("if(OnlyIfOnly)", True, True)
+        test("if (OnlyIf Only)", True, True)
+        
+        kw = Keyword("if",caseless=True)
+        
+        test("IFOnlyIfOnly", False, False)
+        test("If(OnlyIfOnly)", False, True)
+        test("iF (OnlyIf Only)", False, True)
+
+
+
+class ParseExpressionResultsAccumulateTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word,delimitedList,Combine,alphas,nums
+
+        num=Word(nums).setName("num").setResultsName("base10", listAllMatches=True)
+        hexnum=Combine("0x"+ Word(nums)).setName("hexnum").setResultsName("hex", listAllMatches=True)
+        name = Word(alphas).setName("word").setResultsName("word", listAllMatches=True)
+        list_of_num=delimitedList( hexnum | num | name, "," )
+        
+        tokens = list_of_num.parseString('1, 0x2, 3, 0x4, aaa')
+        for k,llen,lst in ( ("base10",2,['1','3']),
+                             ("hex",2,['0x2','0x4']),
+                             ("word",1,['aaa']) ):
+            print k,tokens[k]
+            assert len(tokens[k]) == llen, "Wrong length for key %s, %s" % (k,str(tokens[k].asList()))
+            assert lst == tokens[k].asList(), "Incorrect list returned for key %s, %s" % (k,str(tokens[k].asList()))
+        assert tokens.base10.asList() == ['1','3'], "Incorrect list for attribute base10, %s" % str(tokens.base10.asList())
+        assert tokens.hex.asList() == ['0x2','0x4'], "Incorrect list for attribute hex, %s" % str(tokens.hex.asList())
+        assert tokens.word.asList() == ['aaa'], "Incorrect list for attribute word, %s" % str(tokens.word.asList())
+
+        from pyparsing import Literal, Word, nums, Group, Dict, alphas, \
+            quotedString, oneOf, delimitedList, removeQuotes, alphanums
+
+        lbrack = Literal("(").suppress()
+        rbrack = Literal(")").suppress()
+        integer = Word( nums ).setName("int")
+        variable = Word( alphas, max=1 ).setName("variable")
+        relation_body_item = variable | integer | quotedString.copy().setParseAction(removeQuotes)
+        relation_name = Word( alphas+"_", alphanums+"_" )
+        relation_body = lbrack + Group(delimitedList(relation_body_item)) + rbrack
+        Goal = Dict(Group( relation_name + relation_body ))
+        Comparison_Predicate = Group(variable + oneOf("< >") + integer).setResultsName("pred",listAllMatches=True)
+        Query = Goal.setResultsName("head") + ":-" + delimitedList(Goal | Comparison_Predicate)
+
+        test="""Q(x,y,z):-Bloo(x,"Mitsis",y),Foo(y,z,1243),y>28,x<12,x>3"""
+        
+        queryRes = Query.parseString(test)
+        print "pred",queryRes.pred
+        assert queryRes.pred.asList() == [['y', '>', '28'], ['x', '<', '12'], ['x', '>', '3']], "Incorrect list for attribute pred, %s" % str(queryRes.pred.asList())
+        print queryRes.dump()
+
+class ReStringRangeTest(ParseTestCase):
+    def runTest(self):
+        import pyparsing
+        testCases = (
+            (r"[A-Z]"),
+            (r"[A-A]"),
+            (r"[A-Za-z]"),
+            (r"[A-z]"),
+            (r"[\ -\~]"),
+            (r"[\0x20-0]"),
+            (r"[\0x21-\0x7E]"),
+            (r"[\0xa1-\0xfe]"),
+            (r"[\040-0]"),
+            (r"[A-Za-z0-9]"),
+            (r"[A-Za-z0-9_]"),
+            (r"[A-Za-z0-9_$]"),
+            (r"[A-Za-z0-9_$\-]"),
+            (r"[^0-9\\]"),
+            (r"[a-zA-Z]"),
+            (r"[/\^~]"),
+            (r"[=\+\-!]"),
+            (r"[A-]"),
+            (r"[-A]"),
+            )
+        expectedResults = (
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+            "A",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz",
+            " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
+            " !\"#$%&'()*+,-./0",
+            "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
+            #~ "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ",
+            u'\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe',
+            " !\"#$%&'()*+,-./0",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$-",
+            "0123456789\\",
+            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+            "/^~",
+            "=+-!",
+            "A-",
+            "-A",
+            )
+        for test in zip( testCases, expectedResults ):
+            t,exp = test
+            res = pyparsing.srange(t)
+            #~ print t,"->",res
+            assert res == exp, "srange error, srange(%s)->'%s', expected '%s'" % (t, res, exp)
+
+class SkipToParserTests(ParseTestCase):
+    def runTest(self):
+        
+        from pyparsing import Literal, SkipTo, NotAny, cStyleComment
+        
+        thingToFind = Literal('working')
+        testExpr = SkipTo(Literal(';'), True, cStyleComment) + thingToFind
+        
+        def tryToParse (someText):
+            try:
+                print testExpr.parseString(someText)
+            except Exception, e:
+                print "Exception %s while parsing string %s" % (e,repr(someText))
+                assert False, "Exception %s while parsing string %s" % (e,repr(someText))
+    
+        # This first test works, as the SkipTo expression is immediately following the ignore expression (cStyleComment)
+        tryToParse('some text /* comment with ; in */; working')
+        # This second test fails, as there is text following the ignore expression, and before the SkipTo expression.
+        tryToParse('some text /* comment with ; in */some other stuff; working')
+
+
+class CustomQuotesTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import QuotedString
+
+        testString = r"""
+            sdlfjs :sdf\:jls::djf: sl:kfsjf
+            sdlfjs -sdf\:jls::--djf: sl-kfsjf
+            sdlfjs -sdf\:::jls::--djf: sl:::-kfsjf
+            sdlfjs ^sdf\:jls^^--djf^ sl-kfsjf
+            sdlfjs ^^^==sdf\:j=lz::--djf: sl=^^=kfsjf
+            sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf^^^
+        """
+        colonQuotes = QuotedString(':','\\','::')
+        dashQuotes  = QuotedString('-','\\', '--')
+        hatQuotes   = QuotedString('^','\\')
+        hatQuotes1  = QuotedString('^','\\','^^')
+        dblEqQuotes = QuotedString('==','\\')
+        
+        def test(quoteExpr, expected):
+            print quoteExpr.pattern
+            print quoteExpr.searchString(testString)
+            print quoteExpr.searchString(testString)[0][0]
+            assert quoteExpr.searchString(testString)[0][0] == expected, \
+                    "failed to match %s, expected '%s', got '%s'" % \
+                    (quoteExpr,expected,quoteExpr.searchString(testString)[0])
+        
+        test(colonQuotes, r"sdf:jls:djf")
+        test(dashQuotes,  r"sdf:jls::-djf: sl")
+        test(hatQuotes,   r"sdf:jls")
+        test(hatQuotes1,  r"sdf:jls^--djf")
+        test(dblEqQuotes, r"sdf:j=ls::--djf: sl")
+        test( QuotedString(':::'), 'jls::--djf: sl')
+        test( QuotedString('==',endQuoteChar='--'), 'sdf\:j=lz::')
+        test( QuotedString('^^^',multiline=True), """==sdf\:j=lz::--djf: sl=^^=kfsjf
+            sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf""")
+        try:
+            bad1 = QuotedString('','\\')
+        except SyntaxError,se:
+            pass
+        else:
+            assert False,"failed to raise SyntaxError with empty quote string"
+
+class RepeaterTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import matchPreviousLiteral,matchPreviousExpr, Forward, Literal, Word, alphas, nums
+
+        first = Word("abcdef").setName("word1")
+        bridge = Word(nums).setName("number")
+        second = matchPreviousLiteral(first).setName("repeat(word1)")
+
+        seq = first + bridge + second
+
+        tests = [
+            ( "abc12abc", True ),
+            ( "abc12aabc", False ),
+            ( "abc12cba", True ),
+            ( "abc12bca", True ),
+        ]
+
+        for tst,result in tests:
+            found = False
+            for tokens,start,end in seq.scanString(tst):
+                f,b,s = tokens
+                print f,b,s
+                found = True
+            if not found:
+                print "No literal match in", tst
+            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
+        print
+        seq = first + bridge + second
+        csFirst = seq.setName("word-num-word")
+        csSecond = matchPreviousLiteral(csFirst)
+        compoundSeq = csFirst + ":" + csSecond
+        
+        first = Word("abcdef").setName("word1")
+        bridge = Word(nums).setName("number")
+        second = matchPreviousExpr(first).setName("repeat(word1)")
+        seq = first + bridge + second
+        
+        tests = [
+            ( "abc12abc", True ),
+            ( "abc12cba", False ),
+            ( "abc12abcdef", False ),
+            ]
+
+        for tst,result in tests:
+            found = False
+            for tokens,start,end in seq.scanString(tst):
+                print tokens.asList()
+                found = True
+            if not found:
+                print "No expression match in", tst
+            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
+            
+        print
+        seq = first + bridge + second
+        csFirst = seq.setName("word-num-word")
+        csSecond = matchPreviousExpr(csFirst)
+        compoundSeq = csFirst + ":" + csSecond
+        compoundSeq.streamline()
+        print compoundSeq
+        
+        tests = [
+            ( "abc12abc:abc12abc", True ),
+            ( "abc12cba:abc12abc", False ),
+            ( "abc12abc:abc12abcdef", False ),
+            ]
+
+        for tst,result in tests:
+            found = False
+            for tokens,start,end in compoundSeq.scanString(tst):
+                print tokens.asList()
+                found = True
+            if not found:
+                print "No expression match in", tst
+            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
+            
+        print
+        eFirst = Word(nums)
+        eSecond = matchPreviousExpr(eFirst)
+        eSeq = eFirst + ":" + eSecond
+        
+        tests = [
+            ( "1:1A", True ),
+            ( "1:10", False ),
+            ]
+        
+        for tst,result in tests:
+            found = False
+            for tokens,start,end in eSeq.scanString(tst):
+                #~ f,b,s = tokens
+                #~ print f,b,s
+                print tokens.asList()
+                found = True
+            if not found:
+                print "No match in", tst
+            assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))
+
+class RecursiveCombineTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Forward,Word,alphas,nums,Optional,Combine
+        
+        testInput = "myc(114)r(11)dd"
+        Stream=Forward()
+        Stream << Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream)
+        expected = Stream.parseString(testInput).asList()
+        print ["".join(expected)]
+
+        Stream=Forward()
+        Stream << Combine(Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream))
+        testVal = Stream.parseString(testInput).asList()
+        print testVal
+        
+        assert "".join(testVal) == "".join(expected), "Failed to process Combine with recursive content"
+
+class OperatorPrecedenceGrammarTest1(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word,nums,alphas,Literal,oneOf,operatorPrecedence,opAssoc
+        
+        integer = Word(nums).setParseAction(lambda t:int(t[0]))
+        variable = Word(alphas,exact=1)
+        operand = integer | variable
+
+        expop = Literal('^')
+        signop = oneOf('+ -')
+        multop = oneOf('* /')
+        plusop = oneOf('+ -')
+        factop = Literal('!')
+
+        expr = operatorPrecedence( operand,
+            [("!", 1, opAssoc.LEFT),
+             ("^", 2, opAssoc.RIGHT),
+             (signop, 1, opAssoc.RIGHT),
+             (multop, 2, opAssoc.LEFT),
+             (plusop, 2, opAssoc.LEFT),]
+            )
+
+        test = ["9 + 2 + 3",
+                "9 + 2 * 3",
+                "(9 + 2) * 3",
+                "(9 + -2) * 3",
+                "(9 + --2) * 3",
+                "(9 + -2) * 3^2^2",
+                "(9! + -2) * 3^2^2",
+                "M*X + B",
+                "M*(X + B)",
+                "1+2*-3^4*5+-+-6",
+                "3!!"]
+        expected = """[[9, '+', 2, '+', 3]]
+                    [[9, '+', [2, '*', 3]]]
+                    [[[9, '+', 2], '*', 3]]
+                    [[[9, '+', ['-', 2]], '*', 3]]
+                    [[[9, '+', ['-', ['-', 2]]], '*', 3]]
+                    [[[9, '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]]
+                    [[[[9, '!'], '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]]
+                    [[['M', '*', 'X'], '+', 'B']]
+                    [['M', '*', ['X', '+', 'B']]]
+                    [[1, '+', [2, '*', ['-', [3, '^', 4]], '*', 5], '+', ['-', ['+', ['-', 6]]]]]
+                    [[3, '!', '!']]""".split('\n')
+        expected = map(lambda x:eval(x),expected)
+        for t,e in zip(test,expected):
+            print t,"->",e, "got", expr.parseString(t).asList()
+            assert expr.parseString(t).asList() == e,"mismatched results for operatorPrecedence: got %s, expected %s" % (expr.parseString(t).asList(),e)
+
+class OperatorPrecedenceGrammarTest2(ParseTestCase):
+    def runTest(self):
+
+        from pyparsing import operatorPrecedence, Word, alphas, oneOf, opAssoc
+        
+        boolVars = { "True":True, "False":False }
+        class BoolOperand(object):
+            def __init__(self,t):
+                self.args = t[0][0::2]
+            def __str__(self):
+                sep = " %s " % self.reprsymbol
+                return "(" + sep.join(map(str,self.args)) + ")"
+            
+        class BoolAnd(BoolOperand):
+            reprsymbol = '&'
+            def __nonzero__(self):
+                for a in self.args:
+                    if isinstance(a,basestring):
+                        v = boolVars[a]
+                    else:
+                        v = bool(a)
+                    if not v:
+                        return False
+                return True
+
+        class BoolOr(BoolOperand):
+            reprsymbol = '|'    
+            def __nonzero__(self):
+                for a in self.args:
+                    if isinstance(a,basestring):
+                        v = boolVars[a]
+                    else:
+                        v = bool(a)
+                    if v:
+                        return True
+                return False
+
+        class BoolNot(BoolOperand):
+            def __init__(self,t):
+                self.arg = t[0][1]
+            def __str__(self):
+                return "~" + str(self.arg)
+            def __nonzero__(self):
+                if isinstance(self.arg,basestring):
+                    v = boolVars[self.arg]
+                else:
+                    v = bool(self.arg)
+                return not v
+
+        boolOperand = Word(alphas,max=1) | oneOf("True False")
+        boolExpr = operatorPrecedence( boolOperand,
+            [
+            ("not", 1, opAssoc.RIGHT, BoolNot),
+            ("and", 2, opAssoc.LEFT,  BoolAnd),
+            ("or",  2, opAssoc.LEFT,  BoolOr),
+            ])
+        test = ["p and not q",
+                "not not p",
+                "not(p and q)",
+                "q or not p and r",
+                "q or not p or not r",
+                "q or not (p and r)",
+                "p or q or r",
+                "p or q or r and False",
+                "(p or q or r) and False",
+                ]
+
+        boolVars["p"] = True
+        boolVars["q"] = False
+        boolVars["r"] = True
+        print "p =", boolVars["p"]
+        print "q =", boolVars["q"]
+        print "r =", boolVars["r"]
+        print
+        for t in test:
+            res = boolExpr.parseString(t)[0]
+            print t,'\n', res, '=', bool(res),'\n'
+
+        
+class OperatorPrecedenceGrammarTest3(ParseTestCase):
+    def runTest(self):
+
+        from pyparsing import operatorPrecedence, Word, alphas, oneOf, opAssoc, nums, Literal
+        
+        global count
+        count = 0
+        
+        def evaluate_int(t):
+            global count
+            value = int(t[0])
+            print "evaluate_int", value
+            count += 1
+            return value
+
+        integer = Word(nums).setParseAction(evaluate_int)
+        variable = Word(alphas,exact=1)
+        operand = integer | variable
+
+        expop = Literal('^')
+        signop = oneOf('+ -')
+        multop = oneOf('* /')
+        plusop = oneOf('+ -')
+        factop = Literal('!')
+
+        expr = operatorPrecedence( operand,
+            [
+            ("!", 1, opAssoc.LEFT),
+            ("^", 2, opAssoc.RIGHT),
+            (signop, 1, opAssoc.RIGHT),
+            (multop, 2, opAssoc.LEFT),
+            (plusop, 2, opAssoc.LEFT),
+            ])
+
+        test = ["9"]
+        for t in test:
+            count = 0
+            print "%s => %s" % (t, expr.parseString(t))
+            assert count == 1, "count evaluated too many times!"
+
+class OperatorPrecedenceGrammarTest4(ParseTestCase):
+    def runTest(self):
+
+        import pyparsing
+
+        word = pyparsing.Word(pyparsing.alphas)
+
+        def supLiteral(s):
+            """Returns the suppressed literal s"""
+            return pyparsing.Literal(s).suppress()
+
+        def booleanExpr(atom):
+            ops = [
+                (supLiteral(u"!"), 1, pyparsing.opAssoc.RIGHT, lambda s, l, t: ["!", t[0][0]]),
+                (pyparsing.oneOf(u"= !="), 2, pyparsing.opAssoc.LEFT, ),
+                (supLiteral(u"&"), 2, pyparsing.opAssoc.LEFT,  lambda s, l, t: ["&", t[0]]),
+                (supLiteral(u"|"), 2, pyparsing.opAssoc.LEFT,  lambda s, l, t: ["|", t[0]])]
+            return pyparsing.operatorPrecedence(atom, ops)
+
+        f = booleanExpr(word) + pyparsing.StringEnd()
+
+        tests = [
+            ("bar = foo", "[['bar', '=', 'foo']]"),
+            ("bar = foo & baz = fee", "['&', [['bar', '=', 'foo'], ['baz', '=', 'fee']]]"),
+            ]
+        for test,expected in tests:
+            print test
+            results = f.parseString(test)
+            print results
+            assert str(results) == expected, "failed to match expected results, got '%s'" % str(results)
+            print
+        
+
+class ParseResultsPickleTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import makeHTMLTags
+        import pickle
+        
+        body = makeHTMLTags("BODY")[0]
+        result = body.parseString("<BODY BGCOLOR='#00FFBB' FGCOLOR=black>")
+        print result.dump()
+        print
+        
+        pickleString = pickle.dumps(result)
+        newresult = pickle.loads(pickleString)
+        print newresult.dump()
+        
+        assert result.dump() == newresult.dump(), "Error pickling ParseResults object"
+
+class ParseResultsWithNamedTupleTest(ParseTestCase):
+    def runTest(self):
+
+        from pyparsing import Literal,replaceWith
+
+        expr = Literal("A")
+        expr.setParseAction(replaceWith(tuple(["A","Z"])))
+        expr = expr.setResultsName("Achar")
+
+        res = expr.parseString("A")
+        print repr(res)
+        print res.Achar
+        assert res.Achar == ("A","Z"), "Failed accessing named results containing a tuple, got " + res.Achar
+
+
+class MiscellaneousParserTests(ParseTestCase):
+    def runTest(self):
+        import pyparsing
+        
+        # test making oneOf with duplicate symbols
+        print "verify oneOf handles duplicate symbols"
+        try:
+            test1 = pyparsing.oneOf("a b c d a")
+        except RuntimeError:
+            assert False,"still have infinite loop in oneOf with duplicate symbols"
+        
+        # test MatchFirst bugfix
+        print "verify MatchFirst iterates properly"
+        results = pyparsing.quotedString.parseString("'this is a single quoted string'")
+        assert len(results) > 0, "MatchFirst error - not iterating over all choices"
+            
+        # verify streamline of subexpressions
+        print "verify proper streamline logic"
+        compound = pyparsing.Literal("A") + "B" + "C" + "D"
+        assert len(compound.exprs) == 2,"bad test setup"
+        print compound
+        compound.streamline()
+        print compound
+        assert len(compound.exprs) == 4,"streamline not working"
+        
+        # test for Optional with results name and no match
+        print "verify Optional's do not cause match failure if have results name"
+        testGrammar = pyparsing.Literal("A") + pyparsing.Optional("B").setResultsName("gotB") + pyparsing.Literal("C")
+        try:
+            testGrammar.parseString("ABC")
+            testGrammar.parseString("AC")
+        except pyparsing.ParseException, pe:
+            print pe.pstr,"->",pe
+            assert False, "error in Optional matching of string %s" % pe.pstr
+        
+        # test return of furthest exception
+        testGrammar = ( pyparsing.Literal("A") |
+                        ( pyparsing.Optional("B") + pyparsing.Literal("C") ) |
+                        pyparsing.Literal("D") )
+        try:
+            testGrammar.parseString("BC")
+            testGrammar.parseString("BD")
+        except pyparsing.ParseException, pe:
+            print pe.pstr,"->",pe
+            assert pe.pstr == "BD", "wrong test string failed to parse"
+            assert pe.loc == 1, "error in Optional matching, pe.loc="+str(pe.loc)
+
+        # test validate
+        print "verify behavior of validate()"
+        def testValidation( grmr, gnam, isValid ):
+            try:
+                grmr.validate()
+                assert isValid,"validate() accepted invalid grammar " + gnam
+            except pyparsing.RecursiveGrammarException,e:
+                assert not isValid, "validate() rejected valid grammar " + gnam
+            
+        fwd = pyparsing.Forward()
+        g1 = pyparsing.OneOrMore( ( pyparsing.Literal("A") + "B" + "C" ) | fwd )
+        g2 = pyparsing.ZeroOrMore("C" + g1)
+        fwd << pyparsing.Group(g2)
+        testValidation( fwd, "fwd", isValid=True )
+                    
+        fwd2 = pyparsing.Forward()
+        fwd2 << pyparsing.Group("A" | fwd2)
+        testValidation( fwd2, "fwd2", isValid=False )
+                
+        fwd3 = pyparsing.Forward()
+        fwd3 << pyparsing.Optional("A") + fwd3
+        testValidation( fwd3, "fwd3", isValid=False )
+
+        # test getName
+        print "verify behavior of getName()"
+        aaa = pyparsing.Group(pyparsing.Word("a")).setResultsName("A")
+        bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B")
+        ccc = pyparsing.Group(":" + pyparsing.Word("c")).setResultsName("C")
+        g1 = "XXX" + pyparsing.ZeroOrMore( aaa | bbb | ccc )
+        teststring = "XXX b b a b b a b :c b a"
+        names = []
+        for t in g1.parseString(teststring):
+            #~ print t, repr(t)
+            try:
+                names.append( t[0].getName() )
+            except:
+                try:
+                    names.append( t.getName() )
+                except:
+                    names.append( None )
+        print teststring
+        print names
+        assert names==[None, 'B', 'B', 'A', 'B', 'B', 'A', 'B', 'C', 'B', 'A'], \
+            "failure in getting names for tokens"
+
+        # test ParseResults.get() method
+        print "verify behavior of ParseResults.get()"
+        res = g1.parseString(teststring)
+        print res.get("A","A not found")[0]
+        print res.get("D","!D")
+        assert res.get("A","A not found")[0] == "a", "get on existing key failed"
+        assert res.get("D","!D") == "!D", "get on missing key failed"
+        
+        print "verify handling of Optional's beyond the end of string"
+        testGrammar = "A" + pyparsing.Optional("B") + pyparsing.Optional("C") + pyparsing.Optional("D")
+        testGrammar.parseString("A")
+        testGrammar.parseString("AB")
+        
+        # test creating Literal with empty string
+        print 'verify non-fatal usage of Literal("")'
+        e = pyparsing.Literal("")
+        try:
+            e.parseString("SLJFD")
+        except Exception,e:
+            assert False, "Failed to handle empty Literal"
+
+            
+class ParseHTMLTagsTest(ParseTestCase):
+    def runTest(self):
+        import pyparsing
+        test = """
+            <BODY>
+            <BODY BGCOLOR="#00FFCC">
+            <BODY BGCOLOR="#00FFAA"/>
+            <BODY BGCOLOR='#00FFBB' FGCOLOR=black>
+            <BODY/>
+            </BODY>
+        """
+        results = [ 
+            ("startBody", False, "", ""),
+            ("startBody", False, "#00FFCC", ""),
+            ("startBody", True,  "#00FFAA", ""),
+            ("startBody", False, "#00FFBB", "black"),
+            ("startBody", True, "", ""),
+            ("endBody", False, "", ""),
+            ]
+        
+        bodyStart, bodyEnd = pyparsing.makeHTMLTags("BODY")
+        resIter = iter(results)
+        for t,s,e in (bodyStart | bodyEnd).scanString( test ):
+            print test[s:e], "->", t.asList()
+            (expectedType, expectedEmpty, expectedBG, expectedFG) = resIter.next()
+            
+            tType = t.getName() 
+            #~ print tType,"==",expectedType,"?"
+            assert tType in "startBody endBody".split(), "parsed token of unknown type '%s'" % tType
+            assert tType == expectedType, "expected token of type %s, got %s" % (expectedType, tType) 
+            if tType == "startBody":
+                assert bool(t.empty) == expectedEmpty, "expected %s token, got %s" % ( expectedEmpty and "empty" or "not empty", 
+                                                                                                t.empty and "empty" or "not empty" )
+                assert t.bgcolor == expectedBG, "failed to match BGCOLOR, expected %s, got %s" % ( expectedBG, t.bgcolor )
+                assert t.fgcolor == expectedFG, "failed to match FGCOLOR, expected %s, got %s" % ( expectedFG, t.bgcolor )
+            elif tType == "endBody":
+                #~ print "end tag"
+                pass
+            else:
+                print "BAD!!!"
+
+class UpcaseDowncaseUnicode(ParseTestCase):
+    def runTest(self):
+    
+        import pyparsing as pp
+        import sys
+
+        a = u'\u00bfC\u00f3mo esta usted?'
+        ualphas = u"".join( [ unichr(i) for i in range(sys.maxunicode)
+                            if unichr(i).isalpha() ] )
+        uword = pp.Word(ualphas).setParseAction(pp.upcaseTokens)
+
+        print uword.searchString(a)
+
+        uword = pp.Word(ualphas).setParseAction(pp.downcaseTokens)
+
+        print uword.searchString(a)
+
+
+        #test html data
+        html = "<TR class=maintxt bgColor=#ffffff> \
+            <TD vAlign=top>Производитель, модель</TD> \
+            <TD vAlign=top><STRONG>BenQ-Siemens CF61</STRONG></TD> \
+        ".decode('utf-8')
+
+        # u'Manufacturer, model
+        text_manuf = u'Производитель, модель'
+        manufacturer = pp.Literal(text_manuf)
+
+        td_start, td_end = pp.makeHTMLTags("td")
+        manuf_body =  td_start.suppress() + manufacturer + pp.SkipTo(td_end).setResultsName("cells", True) + td_end.suppress()
+
+        #~ manuf_body.setDebug()
+
+        for tokens in manuf_body.scanString(html):
+            print tokens
+
+class ParseUsingRegex(ParseTestCase):
+    def runTest(self):
+    
+        import re
+        import pyparsing
+        
+        signedInt = pyparsing.Regex('[-+][0-9]+')
+        unsignedInt = pyparsing.Regex('[0-9]+')
+        simpleString = pyparsing.Regex('("[^\"]*")|(\'[^\']*\')')
+        namedGrouping = pyparsing.Regex('("(?P<content>[^\"]*)")')
+        
+        def testMatch (expression, instring, shouldPass, expectedString=None):
+            if shouldPass:
+                try:
+                    result = expression.parseString(instring)
+                    print '%s correctly matched %s' % (repr(expression), repr(instring))
+                    if expectedString != result[0]:
+                        print '\tbut failed to match the pattern as expected:'
+                        print '\tproduced %s instead of %s' % \
+                            (repr(result[0]), repr(expectedString))
+                    return True
+                except pyparsing.ParseException:
+                    print '%s incorrectly failed to match %s' % \
+                        (repr(expression), repr(instring))
+            else:
+                try:
+                    result = expression.parseString(instring)
+                    print '%s incorrectly matched %s' % (repr(expression), repr(instring))
+                    print '\tproduced %s as a result' % repr(result[0])
+                except pyparsing.ParseException:
+                    print '%s correctly failed to match %s' % \
+                        (repr(expression), repr(instring))
+                    return True
+            return False
+        
+        # These should fail
+        assert testMatch(signedInt, '1234 foo', False), "Re: (1) passed, expected fail"
+        assert testMatch(signedInt, '    +foo', False), "Re: (2) passed, expected fail"
+        assert testMatch(unsignedInt, 'abc', False), "Re: (3) passed, expected fail"
+        assert testMatch(unsignedInt, '+123 foo', False), "Re: (4) passed, expected fail"
+        assert testMatch(simpleString, 'foo', False), "Re: (5) passed, expected fail"
+        assert testMatch(simpleString, '"foo bar\'', False), "Re: (6) passed, expected fail"
+        assert testMatch(simpleString, '\'foo bar"', False), "Re: (7) passed, expected fail"
+
+        # These should pass
+        assert testMatch(signedInt, '   +123', True, '+123'), "Re: (8) failed, expected pass"
+        assert testMatch(signedInt, '+123', True, '+123'), "Re: (9) failed, expected pass"
+        assert testMatch(signedInt, '+123 foo', True, '+123'), "Re: (10) failed, expected pass"
+        assert testMatch(signedInt, '-0 foo', True, '-0'), "Re: (11) failed, expected pass"
+        assert testMatch(unsignedInt, '123 foo', True, '123'), "Re: (12) failed, expected pass"
+        assert testMatch(unsignedInt, '0 foo', True, '0'), "Re: (13) failed, expected pass"
+        assert testMatch(simpleString, '"foo"', True, '"foo"'), "Re: (14) failed, expected pass"
+        assert testMatch(simpleString, "'foo bar' baz", True, "'foo bar'"), "Re: (15) failed, expected pass"
+        
+        # This one is going to match correctly, but fail to pull out the correct result
+        #  (for now), as there is no actual handling for extracted named groups
+        assert testMatch(namedGrouping, '"foo bar" baz', True, '"foo bar"'), "Re: (16) failed, expected pass"
+        ret = namedGrouping.parseString('"zork" blah')
+        print ret.asList()
+        print ret.items()
+        print ret.content
+        assert ret.content == 'zork', "named group lookup failed"
+        assert ret[0] == simpleString.parseString('"zork" blah')[0], "Regex not properly returning ParseResults for named vs. unnamed groups"
+        
+        try:
+            #~ print "lets try an invalid RE"
+            invRe = pyparsing.Regex('("[^\"]*")|(\'[^\']*\'')
+        except Exception,e:
+            print "successfully rejected an invalid RE:",
+            print e
+        else:
+            assert False, "failed to reject invalid RE"
+            
+        invRe = pyparsing.Regex('')
+
+class CountedArrayTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word,nums,OneOrMore,countedArray
+        
+        testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3"
+
+        integer = Word(nums).setParseAction(lambda t: int(t[0]))
+        countedField = countedArray(integer)
+        
+        r = OneOrMore(countedField).parseString( testString )
+        print testString
+        print r.asList()
+        
+        assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \
+                "Failed matching countedArray, got " + str(r.asList())
+
+class CountedArrayTest2(ParseTestCase):
+    # addresses bug raised by Ralf Vosseler
+    def runTest(self):
+        from pyparsing import Word,nums,OneOrMore,countedArray
+        
+        testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3"
+
+        integer = Word(nums).setParseAction(lambda t: int(t[0]))
+        countedField = countedArray(integer)
+        
+        dummy = Word("A")
+        r = OneOrMore(dummy ^ countedField).parseString( testString )
+        print testString
+        print r.asList()
+        
+        assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \
+                "Failed matching countedArray, got " + str(r.asList())
+
+class LineAndStringEndTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import OneOrMore,lineEnd,alphanums,Word,stringEnd,delimitedList,SkipTo
+
+        les = OneOrMore(lineEnd)
+        bnf1 = delimitedList(Word(alphanums).leaveWhitespace(),les)
+        bnf2 = Word(alphanums) + stringEnd
+        bnf3 = Word(alphanums) + SkipTo(stringEnd)
+        tests = [
+            ("testA\ntestB\ntestC\n", ['testA', 'testB', 'testC']),
+            ("testD\ntestE\ntestF", ['testD', 'testE', 'testF']),
+            ("a", ['a']),
+             ]
+
+        for t in tests:
+            res1 = bnf1.parseString(t[0])
+            print res1,'=?',t[1]
+            assert res1.asList() == t[1], "Failed lineEnd/stringEnd test (1): "+repr(t[0])+ " -> "+str(res1.asList())
+            res2 = bnf2.searchString(t[0])
+            print res2[0].asList(),'=?',t[1][-1:]
+            assert res2[0].asList() == t[1][-1:], "Failed lineEnd/stringEnd test (2): "+repr(t[0])+ " -> "+str(res2[0].asList())
+            res3 = bnf3.parseString(t[0])
+            print repr(res3[1]),'=?',repr(t[0][len(res3[0])+1:])
+            assert res3[1] == t[0][len(res3[0])+1:], "Failed lineEnd/stringEnd test (3): " +repr(t[0])+ " -> "+str(res3[1].asList())
+
+class VariableParseActionArgsTest(ParseTestCase):
+    def runTest(self):
+        
+        pa3 = lambda s,l,t: t
+        pa2 = lambda l,t: t
+        pa1 = lambda t: t
+        def pa0(): return
+        class Callable3(object):
+            def __call__(self,s,l,t):
+                return t
+        class Callable2(object):
+            def __call__(self,l,t):
+                return t
+        class Callable1(object):
+            def __call__(self,t):
+                return t
+        class Callable0(object):
+            def __call__(self):
+                return 
+        class CallableS3(object):
+            #~ @staticmethod
+            def __call__(s,l,t):
+                return t
+            __call__=staticmethod(__call__)
+        class CallableS2(object):
+            #~ @staticmethod
+            def __call__(l,t):
+                return t
+            __call__=staticmethod(__call__)
+        class CallableS1(object):
+            #~ @staticmethod
+            def __call__(t):
+                return t
+            __call__=staticmethod(__call__)
+        class CallableS0(object):
+            #~ @staticmethod
+            def __call__():
+                return
+            __call__=staticmethod(__call__)
+        class CallableC3(object):
+            #~ @classmethod
+            def __call__(cls,s,l,t):
+                return t
+            __call__=classmethod(__call__)
+        class CallableC2(object):
+            #~ @classmethod
+            def __call__(cls,l,t):
+                return t
+            __call__=classmethod(__call__)
+        class CallableC1(object):
+            #~ @classmethod
+            def __call__(cls,t):
+                return t
+            __call__=classmethod(__call__)
+        class CallableC0(object):
+            #~ @classmethod
+            def __call__(cls):
+                return
+            __call__=classmethod(__call__)
+        
+        class parseActionHolder(object):
+            #~ @staticmethod
+            def pa3(s,l,t):
+                return t
+            pa3=staticmethod(pa3)
+            #~ @staticmethod
+            def pa2(l,t):
+                return t
+            pa2=staticmethod(pa2)
+            #~ @staticmethod
+            def pa1(t):
+                return t
+            pa1=staticmethod(pa1)
+            #~ @staticmethod
+            def pa0():
+                return
+            pa0=staticmethod(pa0)
+                
+        def paArgs(*args):
+            print args
+            return args[2]
+
+        def ClassAsPA0(object):
+            def __init__(self):
+                pass
+            def __str__(self):
+                return "*"
+                
+        def ClassAsPA1(object):
+            def __init__(self,t):
+                self.t = t
+            def __str__(self):
+                return self.t
+                
+        def ClassAsPA2(object):
+            def __init__(self,l,t):
+                self.t = t
+            def __str__(self):
+                return self.t
+                
+        def ClassAsPA3(object):
+            def __init__(self,s,l,t):
+                self.t = t
+            def __str__(self):
+                return self.t
+                
+
+        from pyparsing import Literal,OneOrMore
+        
+        A = Literal("A").setParseAction(pa0)
+        B = Literal("B").setParseAction(pa1)
+        C = Literal("C").setParseAction(pa2)
+        D = Literal("D").setParseAction(pa3)
+        E = Literal("E").setParseAction(Callable0())
+        F = Literal("F").setParseAction(Callable1())
+        G = Literal("G").setParseAction(Callable2())
+        H = Literal("H").setParseAction(Callable3())
+        I = Literal("I").setParseAction(CallableS0())
+        J = Literal("J").setParseAction(CallableS1())
+        K = Literal("K").setParseAction(CallableS2())
+        L = Literal("L").setParseAction(CallableS3())
+        M = Literal("M").setParseAction(CallableC0())
+        N = Literal("N").setParseAction(CallableC1())
+        O = Literal("O").setParseAction(CallableC2())
+        P = Literal("P").setParseAction(CallableC3())
+        Q = Literal("Q").setParseAction(paArgs)
+        R = Literal("R").setParseAction(parseActionHolder.pa3)
+        S = Literal("S").setParseAction(parseActionHolder.pa2)
+        T = Literal("T").setParseAction(parseActionHolder.pa1)
+        U = Literal("U").setParseAction(parseActionHolder.pa0)
+        V = Literal("V")
+        
+        gg = OneOrMore( A | B | C | D | E | F | G | H |
+                        I | J | K | L | M | N | O | P | Q | R | S | T | U | V)
+        testString = "VUTSRQPONMLKJIHGFEDCBA"
+        res = gg.parseString(testString)
+        print res.asList()
+        assert res.asList()==list(testString), "Failed to parse using variable length parse actions"
+        
+        A = Literal("A").setParseAction(ClassAsPA0)
+        B = Literal("B").setParseAction(ClassAsPA1)
+        C = Literal("C").setParseAction(ClassAsPA2)
+        D = Literal("D").setParseAction(ClassAsPA3)
+        
+        gg = OneOrMore( A | B | C | D | E | F | G | H |
+                        I | J | K | L | M | N | O | P | Q | R | S | T | U | V)
+        testString = "VUTSRQPONMLKJIHGFEDCBA"
+        res = gg.parseString(testString)
+        print map(str,res)
+        assert map(str,res)==list(testString), "Failed to parse using variable length parse actions using class constructors as parse actions"
+        
+class EnablePackratParsing(ParseTestCase):
+    def runTest(self):
+        from pyparsing import ParserElement
+        ParserElement.enablePackrat()
+
+class SingleArgExceptionTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import ParseBaseException,ParseFatalException
+        
+        msg = ""
+        raisedMsg = ""
+        testMessage = "just one arg"
+        try:
+            raise ParseFatalException, testMessage
+        except ParseBaseException,pbe:
+            print "Received expected exception:", pbe
+            raisedMsg = pbe.msg
+        assert raisedMsg == testMessage, "Failed to get correct exception message"
+
+
+class KeepOriginalTextTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import makeHTMLTags, keepOriginalText
+        
+        def rfn(t):
+            return "%s:%d" % (t.src, len("".join(t)))
+
+        makeHTMLStartTag = lambda tag: makeHTMLTags(tag)[0].setParseAction(keepOriginalText)
+            
+        # use the lambda, Luke
+        #~ start, imge = makeHTMLTags('IMG')  
+        start = makeHTMLStartTag('IMG')
+
+        # don't replace our fancy parse action with rfn, 
+        # append rfn to the list of parse actions
+        #~ start.setParseAction(rfn)
+        start.addParseAction(rfn)
+
+        #start.setParseAction(lambda s,l,t:t.src)
+        text = '''_<img src="images/cal.png"
+            alt="cal image" width="16" height="15">_'''
+        s = start.transformString(text)
+        print s
+        assert s.startswith("_images/cal.png:"), "failed to preserve input s properly"
+        assert s.endswith("77_"),"failed to return full original text properly"
+
+class PackratParsingCacheCopyTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word,nums,ParserElement,delimitedList,Literal,Optional,alphas,alphanums,ZeroOrMore,empty
+
+        integer = Word(nums).setName("integer")
+        id = Word(alphas+'_',alphanums+'_')
+        simpleType = Literal('int');
+        arrayType= simpleType+ZeroOrMore('['+delimitedList(integer)+']')
+        varType = arrayType | simpleType
+        varDec  = varType + delimitedList(id + Optional('='+integer))+';'
+         
+        codeBlock = Literal('{}')
+         
+        funcDef = Optional(varType | 'void')+id+'('+(delimitedList(varType+id)|'void'|empty)+')'+codeBlock
+         
+        program = varDec | funcDef
+        input = 'int f(){}'
+        results = program.parseString(input)
+        print "Parsed '%s' as %s" % (input, results.asList())
+        assert results.asList() == ['int', 'f', '(', ')', '{}'], "Error in packrat parsing"
+
+class ParseResultsDelTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import OneOrMore, Word, alphas, nums
+        
+        grammar = OneOrMore(Word(nums))("ints") + OneOrMore(Word(alphas))("words")
+        res = grammar.parseString("123 456 ABC DEF")
+        print res.dump()
+        origInts = res.ints.asList()
+        origWords = res.words.asList()
+        del res[1]
+        del res["words"]
+        print res.dump()
+        assert res[1]=='ABC',"failed to delete 0'th element correctly"
+        assert res.ints.asList()==origInts, "updated named attributes, should have updated list only"
+        assert res.words=="", "failed to update named attribute correctly"
+        assert res[-1]=='DEF', "updated list, should have updated named attributes only"
+        
+class WithAttributeParseActionTest(ParseTestCase):
+    def runTest(self):
+        """
+        This unit test checks withAttribute in these ways:
+        
+        * Argument forms as keywords and tuples
+        * Selecting matching tags by attribute
+        * Case-insensitive attribute matching
+        * Correctly matching tags having the attribute, and rejecting tags not having the attribute
+        
+        (Unit test written by voigts as part of the Google Highly Open Participation Contest)
+        """
+        
+        from pyparsing import makeHTMLTags, Word, withAttribute, nums
+        
+        data = """
+        <a>1</a>
+        <a b="x">2</a>
+        <a B="x">3</a>
+        <a b="X">4</a>
+        <a b="y">5</a>
+        """
+        tagStart, tagEnd = makeHTMLTags("a")
+        
+        expr = tagStart + Word(nums).setResultsName("value") + tagEnd
+          
+        expected = [['a', ['b', 'x'], False, '2', '</a>'], ['a', ['b', 'x'], False, '3', '</a>']]
+        
+        for attrib in [
+            withAttribute(b="x"),
+            withAttribute(B="x"),
+            withAttribute(("b","x")),
+            withAttribute(("B","x"))
+            ]:
+          
+          tagStart.setParseAction(attrib)
+          result = expr.searchString(data)
+          
+          print result.dump()
+          assert result.asList() == expected, "Failed test, expected %s, got %s" % (expected, result.asList())
+
+class NestedExpressionsTest(ParseTestCase):
+    def runTest(self):
+        """
+        This unit test checks nestedExpr in these ways:
+        - use of default arguments
+        - use of non-default arguments (such as a pyparsing-defined comment
+          expression in place of quotedString)
+        - use of a custom content expression
+        - use of a pyparsing expression for opener and closer is *OPTIONAL*
+        - use of input data containing nesting delimiters
+        - correct grouping of parsed tokens according to nesting of opening
+          and closing delimiters in the input string
+        
+        (Unit test written by christoph... as part of the Google Highly Open Participation Contest)
+        """
+        from pyparsing import nestedExpr, Literal, Regex, restOfLine, quotedString
+
+        #All defaults. Straight out of the example script. Also, qualifies for
+        #the bonus: note the fact that (Z | (E^F) & D) is not parsed :-).
+        # Tests for bug fixed in 1.4.10
+        print "Test defaults:"
+        teststring = "(( ax + by)*C) (Z | (E^F) & D)"
+
+        expr = nestedExpr()
+
+        expected = [[['ax', '+', 'by'], '*C']]
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected, "Defaults didn't work. That's a bad sign. Expected: %s, got: %s" % (expected, result)
+
+        #Going through non-defaults, one by one; trying to think of anything
+        #odd that might not be properly handled.
+
+        #Change opener
+        print "\nNon-default opener"
+        opener = "["
+        teststring = test_string = "[[ ax + by)*C)"
+        expected = [[['ax', '+', 'by'], '*C']]
+        expr = nestedExpr("[")
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected, "Non-default opener didn't work. Expected: %s, got: %s" % (expected, result)
+
+        #Change closer
+        print "\nNon-default closer"
+
+        teststring = test_string = "(( ax + by]*C]"
+        expected = [[['ax', '+', 'by'], '*C']]
+        expr = nestedExpr(closer="]")
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected, "Non-default closer didn't work. Expected: %s, got: %s" % (expected, result)
+
+        # #Multicharacter opener, closer
+        # opener = "bar"
+        # closer = "baz"
+        print "\nLiteral expressions for opener and closer"
+
+        opener,closer = map(Literal, "bar baz".split())
+        expr = nestedExpr(opener, closer, 
+                    content=Regex(r"([^b ]|b(?!a)|ba(?![rz]))+")) 
+                    
+        teststring = "barbar ax + bybaz*Cbaz"
+        expected = [[['ax', '+', 'by'], '*C']]
+        # expr = nestedExpr(opener, closer)
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected, "Multicharacter opener and closer didn't work. Expected: %s, got: %s" % (expected, result)
+
+        #Lisp-ish comments
+        print "\nUse ignore expression (1)"
+        comment = Regex(r";;.*")
+        teststring = \
+        """
+        (let ((greeting "Hello, world!")) ;;(foo bar
+           (display greeting))
+        """
+
+        expected = [['let', [['greeting', '"Hello,', 'world!"']], ';;(foo bar',\
+                         ['display', 'greeting']]]
+        expr = nestedExpr(ignoreExpr=comment)
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") didn't work. Expected: %s, got: %s" % (expected, result)
+
+
+        #Lisp-ish comments, using a standard bit of pyparsing, and an Or.
+        print "\nUse ignore expression (2)"
+        comment = ';;' + restOfLine 
+
+        teststring = \
+        """
+        (let ((greeting "Hello, )world!")) ;;(foo bar
+           (display greeting))
+        """
+
+        expected = [['let', [['greeting', '"Hello, )world!"']], ';;', '(foo bar', 
+                     ['display', 'greeting']]]
+        expr = nestedExpr(ignoreExpr=(comment ^ quotedString))
+        result = expr.parseString(teststring)
+        print result.dump()
+        assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") and quoted strings didn't work. Expected: %s, got: %s" % (expected, result)
+
+class ParseAllTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import Word
+        
+        testExpr = Word("A")
+        
+        tests = [
+            ("AAAAA", False, True),
+            ("AAAAA", True, True),
+            ("AAABB", False, True),
+            ("AAABB", True, False),
+            ]
+        for s,parseAllFlag,shouldSucceed in tests:
+            try:
+                print "'%s' parseAll=%s (shouldSuceed=%s)" % (s, parseAllFlag, shouldSucceed)
+                testExpr.parseString(s,parseAllFlag)
+                assert shouldSucceed, "successfully parsed when should have failed"
+            except ParseException, pe:
+                assert not shouldSucceed, "failed to parse when should have succeeded"
+        
+class WordBoundaryExpressionsTest(ParseTestCase):
+    def runTest(self):
+        from pyparsing import WordEnd, WordStart, oneOf
+
+        ws = WordStart()
+        we = WordEnd()
+        vowel = oneOf(list("AEIOUY"))
+        consonant = oneOf(list("BCDFGHJKLMNPQRSTVWXZ"))
+
+        leadingVowel = ws + vowel
+        trailingVowel = vowel + we
+        leadingConsonant = ws + consonant
+        trailingConsonant = consonant + we
+        internalVowel = ~ws + vowel + ~we
+
+        bnf = leadingVowel | trailingVowel
+
+        tests = """\
+        ABC DEF GHI
+          JKL MNO PQR
+        STU VWX YZ  """.splitlines()
+        tests.append( "\n".join(tests) )
+
+        expectedResult = [
+            [['D', 'G'], ['A'], ['C', 'F'], ['I'], ['E'], ['A', 'I']],
+            [['J', 'M', 'P'], [], ['L', 'R'], ['O'], [], ['O']],
+            [['S', 'V'], ['Y'], ['X', 'Z'], ['U'], [], ['U', 'Y']],
+            [['D', 'G', 'J', 'M', 'P', 'S', 'V'], 
+             ['A', 'Y'], 
+             ['C', 'F', 'L', 'R', 'X', 'Z'], 
+             ['I', 'O', 'U'], 
+             ['E'],
+             ['A', 'I', 'O', 'U', 'Y']],
+            ]
+            
+        for t,expected in zip(tests, expectedResult):
+            print t
+            results = map(lambda e: flatten(e.searchString(t).asList()), 
+                [
+                leadingConsonant,
+                leadingVowel,
+                trailingConsonant,
+                trailingVowel,
+                internalVowel,
+                bnf,
+                ]
+                )
+            print results
+            assert results==expected,"Failed WordBoundaryTest, expected %s, got %s" % (expected,results)
+            print
+
+
+def makeTestSuite():
+    suite = TestSuite()
+    suite.addTest( PyparsingTestInit() )
+    suite.addTest( ParseIDLTest() )
+    suite.addTest( ParseASMLTest() )
+    suite.addTest( ParseFourFnTest() )
+    suite.addTest( ParseSQLTest() )
+    suite.addTest( ParseConfigFileTest() )
+    suite.addTest( ParseJSONDataTest() )
+    suite.addTest( ParseCommaSeparatedValuesTest() )
+    suite.addTest( ParseEBNFTest() )
+    suite.addTest( ScanStringTest() )
+    suite.addTest( QuotedStringsTest() )
+    suite.addTest( CustomQuotesTest() )
+    suite.addTest( CaselessOneOfTest() )
+    suite.addTest( AsXMLTest() )
+    suite.addTest( CommentParserTest() )
+    suite.addTest( ParseExpressionResultsTest() )
+    suite.addTest( ParseExpressionResultsAccumulateTest() )
+    suite.addTest( ReStringRangeTest() )
+    suite.addTest( ParseKeywordTest() )
+    suite.addTest( ParseHTMLTagsTest() )
+    suite.addTest( ParseUsingRegex() )
+    suite.addTest( SkipToParserTests() )
+    suite.addTest( CountedArrayTest() )
+    suite.addTest( CountedArrayTest2() )
+    suite.addTest( LineAndStringEndTest() )
+    suite.addTest( VariableParseActionArgsTest() )
+    suite.addTest( RepeaterTest() )
+    suite.addTest( RecursiveCombineTest() )
+    suite.addTest( OperatorPrecedenceGrammarTest1() )
+    suite.addTest( OperatorPrecedenceGrammarTest2() )
+    suite.addTest( OperatorPrecedenceGrammarTest3() )
+    suite.addTest( OperatorPrecedenceGrammarTest4() )
+    suite.addTest( ParseResultsPickleTest() )
+    suite.addTest( ParseResultsWithNamedTupleTest() )
+    suite.addTest( ParseResultsDelTest() )
+    suite.addTest( SingleArgExceptionTest() )
+    suite.addTest( UpcaseDowncaseUnicode() )
+    suite.addTest( KeepOriginalTextTest() )
+    suite.addTest( PackratParsingCacheCopyTest() )
+    suite.addTest( WithAttributeParseActionTest() )
+    suite.addTest( NestedExpressionsTest() )
+    suite.addTest( WordBoundaryExpressionsTest() )
+    suite.addTest( ParseAllTest() )
+    suite.addTest( MiscellaneousParserTests() )
+
+    if TEST_USING_PACKRAT:
+        # retest using packrat parsing (disable those tests that aren't compatible)
+        suite.addTest( EnablePackratParsing() )
+        
+        unpackrattables = [ EnablePackratParsing, RepeaterTest, ]
+        
+        # add tests to test suite a second time, to run with packrat parsing
+        # (leaving out those that we know wont work with packrat)
+        packratTests = [t.__class__() for t in suite._tests
+                            if t.__class__ not in unpackrattables]
+        suite.addTests( packratTests )
+        
+    return suite
+    
+
+console = False
+#~ console = True
+if console:
+    #~ # console mode
+    testRunner = TextTestRunner()
+    testRunner.run( makeTestSuite() )
+else:
+    # HTML mode
+    outfile = "testResults.html"
+    outstream = file(outfile,"w")
+    testRunner = HTMLTestRunner.HTMLTestRunner( stream=outstream )
+    testRunner.run( makeTestSuite() )
+    outstream.close()
+
+    import os
+    os.system(outfile)