[hfst] 01/02: Imported Upstream version 3.13.0~r3461

Tino Didriksen tinodidriksen-guest at moszumanska.debian.org
Wed Nov 22 13:49:29 UTC 2017


This is an automated email from the git hooks/post-receive script.

tinodidriksen-guest pushed a commit to branch master
in repository hfst.

commit c3659c061137d93e808d7f51932c8d0093ff16d7
Author: Tino Didriksen <tino at didriksen.cc>
Date:   Wed Nov 22 13:48:55 2017 +0000

    Imported Upstream version 3.13.0~r3461
---
 ChangeLog                                          |   167 +-
 ChangeLog.old                                      |   153 +-
 NEWS                                               |    65 +
 README.rst                                         |    34 +-
 back-ends/foma/cpp-version/Makefile.am             |    45 +
 back-ends/foma/cpp-version/apply.cc                |  1498 +++
 back-ends/foma/cpp-version/coaccessible.cc         |   176 +
 back-ends/foma/cpp-version/constructions.cc        |  3168 ++++++
 back-ends/foma/cpp-version/define.cc               |   147 +
 back-ends/foma/cpp-version/determinize.cc          |   885 ++
 back-ends/foma/cpp-version/dynarray.cc             |   719 ++
 back-ends/foma/cpp-version/extract.cc              |    71 +
 back-ends/foma/cpp-version/flags.cc                |   522 +
 back-ends/foma/cpp-version/foma.cc                 |   266 +
 back-ends/foma/{ => cpp-version}/fomalib.h         |     8 +-
 back-ends/foma/cpp-version/iface.cc                |  1731 +++
 back-ends/foma/cpp-version/int_stack.cc            |    96 +
 back-ends/foma/cpp-version/io.cc                   |  1090 ++
 back-ends/foma/cpp-version/lex.cmatrix.cc          |  2092 ++++
 back-ends/foma/cpp-version/lex.interface.cc        | 10632 +++++++++++++++++++
 back-ends/foma/cpp-version/lex.lexc.cc             |  2934 +++++
 back-ends/foma/cpp-version/lex.yy.cc               |  4209 ++++++++
 back-ends/foma/cpp-version/lexcread.cc             |  1154 ++
 back-ends/foma/cpp-version/mem.cc                  |   104 +
 back-ends/foma/cpp-version/minimize.cc             |   676 ++
 back-ends/foma/cpp-version/regex.cc                |  3345 ++++++
 back-ends/foma/cpp-version/reverse.cc              |    48 +
 back-ends/foma/cpp-version/rewrite.cc              |   610 ++
 back-ends/foma/cpp-version/sigma.cc                |   432 +
 back-ends/foma/cpp-version/spelling.cc             |   880 ++
 back-ends/foma/cpp-version/stack.cc                |   221 +
 back-ends/foma/cpp-version/stringhash.cc           |   101 +
 back-ends/foma/cpp-version/structures.cc           |   922 ++
 back-ends/foma/cpp-version/topsort.cc              |   170 +
 back-ends/foma/cpp-version/trie.cc                 |   151 +
 back-ends/foma/cpp-version/utf8.cc                 |   272 +
 back-ends/foma/fomalib.h                           |     2 +-
 back-ends/openfst/src/include/fst/accumulator.h    |    10 +-
 back-ends/openfst/src/include/fst/arc-map.h        |    10 +-
 back-ends/openfst/src/include/fst/determinize.h    |    10 +-
 back-ends/openfst/src/include/fst/encode.h         |    10 +-
 back-ends/openfst/src/include/fst/epsnormalize.h   |    10 +-
 back-ends/openfst/src/include/fst/equivalent.h     |    10 +-
 back-ends/openfst/src/include/fst/factor-weight.h  |    10 +-
 .../openfst/src/include/fst/label-reachable.h      |    10 +-
 back-ends/openfst/src/include/fst/relabel.h        |    10 +-
 back-ends/openfst/src/include/fst/replace-util.h   |    21 +-
 back-ends/openfst/src/include/fst/replace.h        |    12 +-
 back-ends/openfst/src/include/fst/rmepsilon.h      |    10 +-
 back-ends/openfst/src/include/fst/rmfinalepsilon.h |    10 -
 .../openfst/src/include/fst/sparse-tuple-weight.h  |    12 +-
 back-ends/openfst/src/include/fst/state-map.h      |    10 +-
 .../openfst/src/include/fst/symbol-table-ops.h     |    10 -
 back-ends/openfst/src/include/fst/synchronize.h    |    21 -
 .../openfst/src/include/fst/test-properties.h      |    10 +-
 back-ends/openfst/src/include/fst/unordered_map.h  |    13 +
 back-ends/openfst/src/include/fst/unordered_set.h  |    13 +
 back-ends/openfst/src/include/fst/util.h           |    22 +-
 .../src/include/fst/sparse-tuple-weight.h          |    12 +-
 .../openfstwin/src/include/fst/unordered_map.h     |    14 +-
 .../openfstwin/src/include/fst/unordered_set.h     |    16 +-
 configure.ac                                       |    38 +-
 libhfst/src/HfstDataTypes.cc                       |     1 +
 libhfst/src/HfstExceptionDefs.cc                   |     2 +
 libhfst/src/HfstExceptionDefs.h                    |     3 +-
 libhfst/src/HfstFlagDiacritics.cc                  |     3 +
 libhfst/src/HfstFlagDiacritics.h                   |    30 +-
 libhfst/src/HfstInputStream.cc                     |    70 +-
 libhfst/src/HfstInputStream.h                      |    10 +
 libhfst/src/HfstPrintDot.cc                        |    26 +
 libhfst/src/HfstTransducer.cc                      |    31 +-
 libhfst/src/HfstTransducer.h                       |     6 +
 libhfst/src/HfstXeroxRules.cc                      |     2 +-
 libhfst/src/Makefile.am                            |     2 +-
 .../src/implementations/ConvertFomaTransducer.cc   |     2 +-
 .../implementations/ConvertLogWeightTransducer.cc  |     2 +-
 .../src/implementations/ConvertSfstTransducer.cc   |     2 +-
 .../ConvertTropicalWeightTransducer.cc             |     2 +-
 libhfst/src/implementations/HfstBasicTransducer.cc |     8 +
 libhfst/src/implementations/HfstBasicTransducer.h  |     3 +
 libhfst/src/implementations/HfstOlTransducer.cc    |     7 +-
 libhfst/src/implementations/HfstOlTransducer.h     |     1 +
 libhfst/src/implementations/LogWeightTransducer.cc |     4 +
 libhfst/src/implementations/LogWeightTransducer.h  |     2 +
 libhfst/src/implementations/Makefile.am            |     6 +-
 .../implementations/TropicalWeightTransducer.cc    |    32 +-
 .../src/implementations/TropicalWeightTransducer.h |     2 +
 libhfst/src/implementations/XfsmTransducer.cc      |    10 +-
 .../implementations/optimized-lookup/convert.cc    |     2 +-
 .../src/implementations/optimized-lookup/convert.h |     2 +-
 .../src/implementations/optimized-lookup/pmatch.cc |   721 +-
 .../src/implementations/optimized-lookup/pmatch.h  |   137 +-
 .../optimized-lookup/pmatch_tokenize.cc            |   737 +-
 .../optimized-lookup/pmatch_tokenize.h             |    56 +
 .../implementations/optimized-lookup/transducer.cc |    14 +-
 .../implementations/optimized-lookup/transducer.h  |    24 +
 libhfst/src/parsers/PmatchCompiler.cc              |     3 +-
 libhfst/src/parsers/PmatchCompiler.h               |     3 +
 libhfst/src/parsers/SfstAlphabet.h                 |    16 +-
 libhfst/src/parsers/SfstBasic.cc                   |     2 +-
 libhfst/src/parsers/SfstCompiler.cc                |    20 +-
 libhfst/src/parsers/SfstCompiler.h                 |     6 +-
 libhfst/src/parsers/TwolcCompiler.cc               |   167 +-
 libhfst/src/parsers/TwolcCompiler.h                |    30 +-
 libhfst/src/parsers/XfstCompiler.cc                |   104 +-
 libhfst/src/parsers/XfstCompiler.h                 |    12 +-
 libhfst/src/parsers/commandline_src/CommandLine.cc |     1 +
 libhfst/src/parsers/compile-parsers-win.sh         |    48 +
 libhfst/src/parsers/htwolcpre1-lexer.ll            |    13 +-
 libhfst/src/parsers/htwolcpre1-parser.yy           |    28 +-
 libhfst/src/parsers/htwolcpre2-lexer.ll            |    15 +-
 libhfst/src/parsers/htwolcpre2-parser.yy           |    16 +-
 libhfst/src/parsers/htwolcpre3-lexer.ll            |     4 +-
 libhfst/src/parsers/htwolcpre3-parser.yy           |    47 +-
 libhfst/src/parsers/io_src/InputReader.cc          |    10 +
 libhfst/src/parsers/io_src/InputReader.h           |     2 +
 libhfst/src/parsers/pmatch_lex.ll                  |    10 +
 libhfst/src/parsers/pmatch_parse.yy                |    74 +-
 libhfst/src/parsers/pmatch_utils.cc                |   393 +-
 libhfst/src/parsers/pmatch_utils.h                 |    36 +-
 libhfst/src/parsers/sfst-compiler.yy               |     4 +-
 libhfst/src/parsers/sfst-scanner.ll                |     2 +-
 libhfst/src/parsers/xfst-lexer.ll                  |     4 +-
 libhfst/src/parsers/xfst-parser.yy                 |   660 +-
 libhfst/src/parsers/xre_parse.yy                   |     8 +-
 man/hfst-reweight-tagger.1                         |     2 +-
 python/Makefile.am                                 |     6 +-
 python/README                                      |    29 +-
 python/doc/Doxyfile                                |     2 +-
 python/doc/hfst/__init__.py                        |    98 +-
 python/docstrings.i                                |    27 +-
 python/hfst/__init__.py                            |   105 +-
 python/{hfst_extensions.cc => hfst_extensions.cpp} |     0
 ...file_extensions.cc => hfst_file_extensions.cpp} |     0
 ...lexc_extensions.cc => hfst_lexc_extensions.cpp} |     0
 ...up_extensions.cc => hfst_lookup_extensions.cpp} |     0
 ...ch_extensions.cc => hfst_pmatch_extensions.cpp} |     0
 ...og_extensions.cc => hfst_prolog_extensions.cpp} |     0
 ...gex_extensions.cc => hfst_regex_extensions.cpp} |     0
 ...les_extensions.cc => hfst_rules_extensions.cpp} |     0
 ...sfst_extensions.cc => hfst_sfst_extensions.cpp} |     0
 ...xfst_extensions.cc => hfst_xfst_extensions.cpp} |     0
 python/libhfst.i                                   |    32 +-
 python/pypi/MANIFEST.in                            |    25 +-
 python/pypi/README.rst                             |   129 +-
 python/pypi/copy-files-win.sh                      |    69 +
 python/pypi/copy-files.sh                          |    41 +-
 python/pypi/setup.py                               |   278 +-
 python/setup.py                                    |    32 +-
 python/test/Makefile.am                            |     6 +-
 python/test/test.sh                                |   112 +-
 .../test/test5 => python/test/test1.twolc          |     2 +-
 .../test/test5 => python/test/test2.twolc          |     2 +-
 .../test/test5 => python/test/test3.twolc          |     2 +-
 python/test/test_att_reader.py                     |    15 +
 python/test/test_dir_hfst.py                       |     4 +
 python/test/test_dir_hfst_exceptions.py            |     4 +
 python/test/test_dir_hfst_sfst_rules.py            |     4 +
 python/test/test_examples.py                       |     1 +
 python/test/test_exceptions.py                     |     4 +
 python/test/test_hfst.py                           |    48 +-
 python/test/test_pmatch.py                         |     4 +
 python/test/test_prolog.py                         |     5 +-
 python/test/test_prolog_reader.py                  |     4 +
 python/test/test_read_att_transducer.py            |     4 +
 python/test/test_streams_1.py                      |     6 +-
 python/test/test_streams_2.py                      |     6 +-
 python/test/test_streams_3.py                      |     6 +-
 python/test/test_tokenizer.py                      |     6 +-
 python/test/test_twolc.py                          |    12 +
 python/test/test_xerox_rules.py                    |     4 +
 python/test/test_xre.py                            |     4 +
 python/test/testfile_unicode.att                   |     2 +
 scripts/copy-for-windows.sh                        |     4 +-
 scripts/finnish-tagtools/finnish-nertag            |    60 +
 scripts/finnish-tagtools/finnish-postag            |    45 +
 scripts/finnish-tagtools/finnpos-ratna-feats.py    |   181 +
 scripts/finnish-tagtools/finnpos-restore-lemma.py  |    69 +
 scripts/finnish-tagtools/move_tags                 |     2 +
 scripts/finnish-tagtools/omorfi2finnpos.py         |   128 +
 scripts/finnish-tagtools/prefilt_tags              |    22 +
 scripts/finnish-tagtools/remove_exc                |     2 +
 scripts/finnish-tagtools/tokenize.py               |    31 +
 test/tools/fsmbook-tests/CompileOptions.py         |    25 +
 test/tools/fsmbook-tests/Makefile.am               |     4 +
 test/tools/fsmbook-tests/compare.py                |    35 +
 test/tools/fsmbook-tests/compile_xfst.py           |    27 +
 .../expected-results/FinnishNumerals.prolog        |   326 +
 .../expected-results/FinnishProsody.prolog         |   532 +
 .../expected-results/Palindromes.prolog            |    23 +
 test/tools/fsmbook-tests/fst2fst.py                |    36 +
 test/tools/fsmbook-tests/fst2strings.py            |    15 +
 test/tools/fsmbook-tests/fst2strings_space.py      |    23 +
 test/tools/fsmbook-tests/list_formats.py           |    21 +
 test/tools/fsmbook-tests/prolog2fst.py             |    43 +
 .../python-scripts/BetterColaMachine.hfst.py       |     5 +
 .../python-scripts/BrazilianPortuguese1.hfst.py    |    46 +
 .../python-scripts/BrazilianPortuguese2.hfst.py    |    45 +
 .../python-scripts/DateParser.hfst.py              |    82 +
 .../python-scripts/EinsteinsPuzzle.hfst.py         |   127 +
 .../python-scripts/EnglishNumerals.hfst.py         |    57 +
 .../python-scripts/EsperantoAdjectives.hfst.py     |    15 +
 .../python-scripts/EsperantoNouns.hfst.py          |    17 +
 .../EsperantoNounsAdjectivesAndVerbs.hfst.py       |    53 +
 .../EsperantoNounsAndAdjectives.hfst.py            |    33 +
 .../EsperantoNounsAndAdjectivesWithTags.hfst.py    |    38 +
 .../python-scripts/FinnishNumerals.hfst.py         |    47 +
 .../python-scripts/FinnishOTProsody.hfst.py        |   229 +
 .../python-scripts/FinnishProsody.hfst.py          |   126 +
 .../fsmbook-tests/python-scripts/Lingala.hfst.py   |   154 +
 .../python-scripts/MonishAnalysis.hfst.py          |    48 +
 .../python-scripts/MonishGuesserAnalyzer.hfst.py   |    37 +
 .../python-scripts/NumbersToNumerals.hfst.py       |    60 +
 .../python-scripts/Palindromes.hfst.py             |    46 +
 .../python-scripts/PlusOrMinus.hfst.py             |    49 +
 .../python-scripts/YaleShooting.hfst.py            |   114 +
 test/tools/fsmbook-tests/test.sh                   |   456 +-
 test/tools/pmatch-functionality.sh                 |     4 +-
 test/tools/pmatch-tests.sh                         |   424 +-
 test/tools/pmatch2fst-functionality.sh             |    50 +-
 ...nize-backtrack-out-giella-cg-contiguous.strings |     6 +-
 ...tokenize-backtrack-out-giella-cg-spaces.strings |     2 +-
 .../tools/tokenize-backtrack-out-giella-cg.strings |    14 +-
 test/tools/tokenize-backtrack.lexc                 |    58 +-
 test/tools/tokenize-dog-in.lexc                    |    28 +-
 test/tools/tokenize-dog-out-cg.strings             |     8 +-
 .../tokenize-dog-out-giella-cg-flushing.strings    |     2 +-
 .../tokenize-dog-out-giella-cg-superblank.strings  |     2 +-
 test/tools/tokenize-dog-out-giella-cg.strings      |    12 +-
 test/tools/tokenize-dog-out-xerox.strings          |     8 +-
 tools/src/hfst-optimized-lookup.cc                 |    30 +-
 tools/src/hfst-pmatch.cc                           |    98 +-
 tools/src/hfst-pmatch2fst.cc                       |    11 +-
 .../src/hfst-tagger/src/use_model_src/DataTypes.h  |    31 +-
 .../src/use_model_src/NewLexicalModel.h            |    29 +-
 tools/src/hfst-tokenize.cc                         |   833 +-
 tools/src/hfst-twolc/src/hfst-twolc.cc             |     2 +
 tools/src/hfst-twolc/test/test5                    |     2 +-
 tools/src/hfst-twolc/test/test5.txt_fst            |    30 +-
 tools/src/parsers/hfst-xfst.cc                     |    16 +-
 tools/src/parsers/test/Makefile.am                 |     5 +-
 tools/src/parsers/test/define_fail.xfst            |     3 -
 tools/src/parsers/test/negate_net.att              |    33 -
 tools/src/parsers/test/negate_net_1.att            |    11 +
 .../test/{negate_net.xfst => negate_net_1.xfst}    |     5 +-
 tools/src/parsers/test/negate_net_2.att            |    11 +
 .../test/{negate_net.xfst => negate_net_2.xfst}    |     5 +-
 .../test/{negate_net.xfst => negate_net_fail.xfst} |     0
 tools/src/parsers/test/test.sh                     |    36 +-
 tools/src/sfst-main.cc                             |     2 +-
 250 files changed, 46891 insertions(+), 3430 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 289434e..cc8c8d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,169 @@
-56534b3 (HEAD -> master, origin/master, origin/HEAD) Add missing file.
+f6bc1cd (HEAD -> master, origin/master, origin/HEAD) -W/--no-weights overrides earlier -w (or -w implied by -g) options
+cb9916d Add missing files.
+c92bcaf Add missing files to dist.
+d98ffa7 Initial commit of finnish-tagtools scripts Includes a few ones from FinnPos modified for our purposes
+ee4662b Merge branch 'master' of https://github.com/hfst/hfst
+d6a247e Added a variable "xerox-composition", default to "on"
+355aaf9 allow creating HfstInputStream's from std::istream's
+8ff49aa Use libreadline in hfst-pmatch when available
+b5b7995 [].with(X = Y) feature in pmatch This provides support in the pmatch2fst compiler to define "global flags" with the syntax [your expression here].with(X = Y). This will set up a flag diacritic readable from anywhere within the brackets, even if Ins()ed.
+0858e63 Support getting a list of operations involved with a particular feature. This also involves making define_diacritic() redefine the meaning of symbols if called multiple times on the same symbol number.
+4d4471d tokenize tests should pass again
+f81dcb5 tokenize --giella-cg: assume FST handles space around tags
+b07c47b Merge branch 'master' of https://github.com/hfst/hfst
+60e5c28 Check for success of the now-working test suite.
+acf3c78 Cleanup of remainder of the pmatch test suite Many cases of adding set "need-separators off"; many cases of fixing mistaken test assumptions; one case of fixing code; one case of removing test that was already in pmatch2fst-functionality.sh; one case of removing entire test because it was trying to do something impossible; one case of relaxing test assumptions that should be possibly revisited. Multiple FIXMEs left but all the tests now pass.
+2669274 Make both-sided OptCap() be actually both-sided. It still doesn't downcase the continuation of words, which is possibly a bug.
+64a1874 tokenize --giella-cg: remove as_cg_tag, just need is_cg_tag now
+9decc11 Modify check for list symbols. It was conflicting with left markers for Xerox rules (@LM@), causing a test to very surprisingly break (it didn't even seem to be using optimized-lookup format at all..)
+4e4ba7c Add tests for Lst() and Exc()
+7a0176a Avoid keeping an extra copy of the tokenizing dictionary in memory (fixes https://github.com/hfst/hfst/issues/362)
+8c10e1d Consider list symbols (@L..." and "@X...") to be special
+e4dff09 hfst-tokenize --giella-cg, is_tag: check if symbol Multichar_symbol
+3ec59da tokenize --giella-cg: non-verbose as default
+862ea0e Add C and C++ dlls to dist.
+d653123 Fix misspelling of nrc for nlc
+c005a4a Merge branch 'master' of https://github.com/hfst/hfst
+86dcec6 Fix runtime handling of contexts and compilation of negative contexts. This was broken when the processing state stack was changed to accommodate "RTN safety". The local state is now pushed into a stack when entering a context and pushed again when exiting it, and popped when backtracking out of those situations.
+10967c4 set need-delimiters no for more tests that were broken by it
+06cbb20 Made Xerox output of unknowns follow Xerox
+97ecf44 Merge pull request #359 from kartikm/patch-1
+23dcc54 Fixed typo
+134d5a5 Works around issue #358
+21b0e82 Actually support multiple different Capture() names
+be9e214 Instead of names, use pointers to the calling transducers for rtn calls
+34bf445 Don't track returns from Ins() arcs in the call stack Pushing returns from Ins() calls to the call stack were clobbering nested calls. This is unnecessary, because we have the necessary information about the correct return location from the stack depth variable anyway.
+1358576 Use hfst-pmatch --newline in the tests so we don't see irrelevant blank lines
+e6f7067 Decrement recursion counter when returning from main loop due to no input
+528952f A somewhat hacky fix to a bug introduced by changes to RTN processing pmatch is lacking recursion depth with each RTN entered. This is mostly a problem due to eventually running out of depth and truncating results. For now we reset depth at the start of each input, which makes sense anyway, but the leak should really be fixed.
+c45f620 In locate mode, omit blank lines even if in blankline mode if we didn't print anything
+74f3a6f Remember captures for the duration of the entire input. Also avoid copying the captured vectors around, instead passing iterators to input
+01c2fd7 Fix short form of end tagging also disable automatic disabling of need-separators when encountering a context
+f2b6c8c Merge branch 'master' of https://github.com/hfst/hfst
+64528f7 In blankline-separated mode, keep blanklines in output too
+b0a17a2 Merge branch 'master' of https://github.com/hfst/hfst
+31f0767 Include pre-swig-generated wrappers to source distribution. Update README.
+de22111 Remove bashisms that was breaking tests that apparently are not run with bash
+368acef Fix tokenize backtrack regression, need to handle @PMATCH_BACKTRACK@ explicitly
+da0ab47 Fix test which was probably written with a misunderstanding of replace rules
+ed5ac3b Reinstate and fix some tests by moving them from pmatch-tests.sh (where escaping done by the testing script breaks some tests) to pmatch2fst-functionality.sh
+882ee74 Allow term complement of named transducers
+2686525 Merge branch 'master' of https://github.com/hfst/hfst
+215a482 Support backreferences (Capture())
+eea79b8 Update README.
+e1d519c Link to exact place in page.
+27d3e1c Update README.
+2e93516 For installation instructions, link to PyPI pages instead of KitWiki.
+b68f146 Update README.
+7a3618e Make Like() and Unlike() much faster by not sorting the whole vocabulary (by doing an insertion sort of the n best words) and only calculating each comparison key once
+85f8a8c Fixed binding of freely insert operator in hfst-twolc.
+83eea8b Remove unnecessary (debug?) prints.
+e10be33 Actually use other than ascii characters in att file.
+5102d2d Fix some typos in test.sh. Replace epsilon with empty string in fst2strings.py. Read input in utf-8 format in prolog2fst.py, if possible.
+394284b Fix a typo.
+b52f348 Test if hfst-xfst exists after all options are processed.
+cdaa748 Implement an equivalent python script for all command line tools needed in tests.
+c6dae7a When using python for tests, also replace part of command line tools with equivalent python scripts.
+88a70d3 Fix a couple of typos.
+ef65667 Update python package version number. Use .cpp extension.
+7bc8e18 Update README.
+778ebca Get rid of unnecessary CommandLine in python api. Fix some typos.
+1c345ef Error functions are void, not int.
+b8edb3a Import sys.version_info before using it...
+6a2107c Use extension cpp for all c++ files in pypi package. Also use the c++ implementation of foma backend by default.
+4319046 A couple more fixes.
+3f63a4e Fix some issues noticed by clang.
+27c30ee Add a c++ version of foma backend for testing.
+31c91c3 Add arguments to function declaration.
+0b46845 Fix a couple more typos.
+a117e05 Fix some typos.
+7604850 Improve test script and add expected results for cases where xfst solution does not exist but the result from hfst script is checked.
+c459207 Add two more python implementations for fsmbook tests.
+c75cbb8 Merge branch 'master' of https://github.com/hfst/hfst
+61be454 Add Unlike() operation, which could be better named also add option for whether information about cosine distances should be included in the result when compiling word vector operations
+87cb7d6 Two more python tests...
+42ba171 Add two more python tests.
+221f8dc Add more tests.
+e25e2d4 Add python test for FinnishNumerals
+7d917a4 Allow empty string as input for hfst.fst and hfst.fsa and interpret it as epsilon.
+3842501 Use xfst instead of python for slow tests.
+5962b3a Add one more python test.
+7b3dccb Add python test.
+dd5ed1f Fix broken test assumption
+a45a97d Prohibit EndTagging printable-empty lengths of input
+77d5c7b Fix single-character transducers not getting automatic context separators
+432d16c Verbose message about automatic separators
+7bf07dd Make using Ins() -arcs safe Ins() arcs are no longer locally greedy, so there is no semantic difference between network inclusion with Ins() or by explicitly embedding. eg. define greedy "a+"; now the following work the same way: Ins(greedy) {abc} greedy {abc}
+adc3b0b Use temp weights rather than subtractions like in pmatch
+1378513 Fix test by having need-separators off
+849d297 Minimize automatic delimiter contexts
+97a7b05 Merge pull request #352 from unhammer/tokenise-lib
+2fcc665 Merge branch 'master' into tokenise-lib
+ef026f1 Add option --silent to tests.
+c0996a8 Add .0000000000 to tests; ToDo: Trim trailing 0 after the dot, then trim the dot; ToDo: Investigate where std::fixed gets disabled
+1fe2af9 Wrap compile_twolc_file inside a class as TwolcCompiler::compile.
+dbd0d14 Revert "Removed rounding"
+813f2d3 Add keyword arguments to compile_twolc_file.
+786af19 Removed rounding
+702425e Add twolc files to pypi setup.
+30e3c4f Fix a typo.
+e8acc1a Flush and close the stream.
+2b26a3b Add tests for 'compile_twolc_file'.
+b27f993 Remember to reset also the second parser.
+7fb07f5 Add a possibility to reset twolc parsers between reading several twolc files.
+251cef5 Add option --local-hfst to setup.py.
+87a77e7 Add a tentative implementation of twolc compilation.
+4567609 Make code clearer and add documentation.
+8738272 Keep track of weights along context checking paths and unify weight handling
+539592b Merge branch 'master' of https://github.com/hfst/hfst
+31950de Add beam mode to result filtering
+532925d Make sure TOP has the right name if it's eg. loaded from a @bin""
+dc9bf4e Make sure the HfstTransducer name and the container names match
+5289eb3 Fixes issue 353. Unbelievably, the return value for a weight-returning get_weight() was bool, which after casting mostly worked until it ran into negative weights.
+2bfb55c Fix problem with rtns that are referred but not really present
+2dd7767 Improve help messages of scripts.
+1548480 Add hfst-specific options --with-c++11 and --without-c++11 to setup.py.
+f285400 Use HFST_THROW macro instead of plain throw for HfstExceptions.
+4be886d If USE_FOMA_EPSILON_REMOVAL is defined, use foma for epsilon removal in minimization for unweighted TropicalWeightTransducers to make it faster.
+7b03fd0 Add an option --verbose to test.sh.
+5463306 Fix the way unordered containers are used on windows with python2.7.
+48de6fd Give pythonpath as first optional argument for each test, except for stream tests that take it as a second optional argument. Also specify coding for each test.
+dbb055f round weight to zero decimals, non-sci, in cg/giellacg vislcg3 doesn't (yet) accept floating point weights
+8d38925 Use by default c++11 unordered_map and unordered_set, unless otherwise specified via definitions (INCLUDE_TR1_UNORDERED_MAP_AND_SET and USE_TR1_UNORDERED_MAP_AND_SET).
+31cd16c Merge branch 'master' of https://github.com/hfst/hfst
+8f17d4e Add boolean CPP_STD_11=True to control c++11 support.
+baec687 Move tokenize to correct alphabetical place.
+194b9cc Couple of fixes to vc 2008 compilation without c++11 support.
+38ad594 Fix issues noticed when compiling without c++11 support with VC 2008 on Windows.
+89ddca2 Merge branch 'master' of https://github.com/hfst/hfst
+8121be6 Fixed bug 341 (priority union)
+318fdb5 Add an option --without-c++11 (defaults to 'no') to compile hfst without c++11 support.
+d3a5c5d c++ standard is set in configure, do not set it here
+ee84e29 make hfst-tokenise usable as a lib; include simple string→string fn
+fbf8d49 Update documentation and setup.
+9617edb Add a quick fix to missing 'strtof' in msvc 2012.
+b22626e Add a function cross_product that takes an iterable object of transducers. Document other similar functions.
+b1fbf8b Add simple help messages.
+195ef73 Add a function 'compose' that takes a list of transducers. Comment out a debug print.
+8cb5ee5 Skip calculate_funtionality.py test until it is fixed.
+b9aa618 Add a script that copies files needed for creating a distribution for windows.
+72b1463 Add a script for generating cc and hh files from yacc/flex sources for windows. Update copy script for windows. Change flex token ECHO to ECHO_ to prevent collision with flex/yacc macro with the same name.
+0b61a94 Make script faster.
+06a6c9d More fsmbook python scripts.
+88cc5bf Add a simple --help message to test.sh. Add python versions of two tests.
+3649018 Add new python scripts.
+3ec8d35 If --python is requested in test.sh, use python API also for hfst scripts that have an equivalent python script.
+0ebc87e Add options --python and --pythonpath to test.sh which enable compiling xfst files also via the python API.
+7266f93 Add an example for HfstBasicTransducer.remove_transition.
+f2a547f clang requires libc++ and osx version >= 10.7.
+9a60444 Add function HfstBasicTransducer.remove_final_weight and document it. Also improve documentation of HfstBasicTransducer.remove_transition and HfstBasicTransducer.add_transition.
+a2dbe8e Add function HfstBasicTransducer::remove_final_weight.
+9950d90 Add option --restricted-mode (-R) to hfst-xfst. If it is requested, Write and read operations are allowed only in current directory (i.e. pathnames cannot contain '/' or '\') and system calls are disabled.
+059b5b0 Add tests for hfst-xfst's 'negate' command.
+cdab3f7 Add a function HfstTransducer::negate() which is equivalent to [?* - A] (where A is the transducer) with the exception that flag diacritics are treated as ordinary symbols. Use the function to implement 'negate' command of hfst-xfst.
+4001b45 Allow complement/negation only for automata.
+a741bdc (tag: v3.12.2) Ready for release 3.12.2.
+56534b3 Add missing file.
 cc2dea5 Merge branch 'master' of https://github.com/hfst/hfst
 22383de Check more carefully which backends are actually enabled.
 4cebb75 Actually remove commented code instead of making it visible.
diff --git a/ChangeLog.old b/ChangeLog.old
index 0247c9f..289434e 100644
--- a/ChangeLog.old
+++ b/ChangeLog.old
@@ -1,4 +1,155 @@
-77c845d (HEAD -> master, origin/master, origin/HEAD) Fix flag elimination bug (reported in issue #342).
+56534b3 (HEAD -> master, origin/master, origin/HEAD) Add missing file.
+cc2dea5 Merge branch 'master' of https://github.com/hfst/hfst
+22383de Check more carefully which backends are actually enabled.
+4cebb75 Actually remove commented code instead of making it visible.
+c811b35 Remove commented code.
+357ab0f Remove commented code.
+f9796b3 Update README.
+60742c4 Add extra compile option -std=c++0x.
+25ce84e Reapply changes in commit de59747. Require at least automake 1.12, unless building from pre-yacc-generated sources.
+750a3ca Revert changes in commit de59747. Allow automake older than 1.12.
+0ae7b1e Use std::unordered_map instead of hash_map.
+0b3a248 Use unordered_map instead of hash_map.
+8b4b1d4 Skip lexc wrapper test.
+d11b00e Add a simple exception handling mechanism.
+02e16cb Fix a typo.
+de59747 Stop supporting automake < 1.12. Warn that build will fail unless building with pre-flex-generated sources.
+e776ecc Remove commented code. Remove unnecessary variables.
+8b30936 Skip hfst-train-tagger and hfst-twolc-loc tools in version and help message testing.
+ba28c39 Add missing file to dist.
+b29e140 Remove lexc wrapper tests.
+4033c44 Disable lexc and foma wrappers unless explicitly requested. Fix a typo in --enable-expand-equivalences.
+5035132 Actually enable hfst-calculate and hfst-xfst by default as promised in commit 244b9b5...
+31fc7c7 Add missing condition.
+5191c88 Add option --with-openfst-log=lean to configure which supports only reading, writing and converting log openfst transducers.
+30d3792 Actually check if --with-sfst=lean is configured when compiling sfst functions.
+94eda73 Add configure option --with-sfst=lean which supports a limited set of sfst functions (reading, writing and converting between formats).
+5df548e Add missing const to definition, remove second argument of HFST_THROW.
+214ab27 Add function 'has_weights'. Make function 'get_profile_seconds' public.
+a27f845 Add function 'get_profile_seconds' for profiling foma back-end.
+1b64f33 Add function 'has_weights' and make function 'get_profile_seconds' static.
+244b9b5 Remove duplicate of AC_ARG_ENABLE([xfst]). Enable hfst-calculate and hfst-xfst by default.
+e47f010 Remove commented code. Make sure that code compiles when openfst backend is disabled. Add comments to some functions.
+d0a1e91 Use iosfwd header instead of iostream when possible. Try to include only header files that are actually needed.
+389679d Clean temporary files generated by tests. Add some files to be ignored.
+610572f Merge branch 'master' of https://github.com/hfst/hfst
+f66f396 Check for nested context conditions, ignoring the inner ones
+d8db552 Update man pages. Remove man pages of tools that are no longer supported. Update copyright year.
+62da656 Disable hfst-twolc script and hfst-train-tagger tool unless explicitly enabled with --enable-twolc-script and --enable-train-tagger.
+e369608 Add files to be ignored.
+142bfca By default, implement hfst-twolc as a single program and disable the script (can be controlled via --enable-twolc-script).
+98e08f6 Get rid of hfst-twolc-system tool. The script hfst-twolc will soon be replaced by a single program.
+e30202c Update windows scripts according to recent changes in twolc processing.
+d676043 Update files ignored by git.
+ae820a5 Revert to earlier version of htwolc-main.cc which calls twolc parsers directly instead of TwolcCompiler class. The latter approach sometimes causes a segmentation fault.
+d96b441 Define warning and error streams in TwolcCompiler constructor.
+9c0cca4 Throw an error instead of calling exit(1) when parsing input.
+b820f11 Handle twolc error and warning streams.
+e116a74 Add TwolcCompiler class and use it in htwolc program. Move CommandLine under libhfst/src/parsers.
+9a19088 Move most twolc code from tools/src to libhfst/src/parsers.
+0705bec if no --superblanks, newlines won't be in [], so need to print on unblanked newlines
+1351257 --giella-cg: only treat superblanks if given --superblanks
+efa0964 Update list of files ignored by git.
+19fd1d1 Add an option to use htwolc in twolc tests. Disable it by default.
+59cfdce Rename twolc files.
+a6029ef Rename twolc parser and lexer files. Move functions under namespace hfst::twolcpre[1|2|3].
+5844621 Actually exclude htwolc from installation.
+7661b38 Add an alternative implementation of hfst-twolc which does all processing in a single program. Exclude it from installation until it is properly tested.
+52d5257 only warn for backtrack-on-substrings-without-analyses if --verbose
+3936fdb Control output of htwolcpre1.
+0cc7582 Change names of extern twolc variables and add functions to access some of them.
+f9a69b2 Add missing new file hfst_sfst_extensions.cc.
+d5baf5a Separate twolc parsing and command line tools to their own files.
+035b6ab Use separate prefixes in twolc lexers and parsers.
+d3c4de9 Handle '^<' and '^>' operators in lexc regular expressions correctly. Should fix issue #346.
+6165347 Space-separated mode
+144a3f3 Ignore generated sfst source files.
+dc90602 Merge branch 'master' of https://github.com/hfst/hfst
+9f7208b Improve pmatch compilation error handling, still leaks memory at exit
+3767b51 Add new function 'compile_sfst_file'.
+512245b Merge branch 'master' of https://github.com/hfst/hfst
+4649b83 Reorder and add norm caching
+460cded clearer error message for when there is backtracking into substrings that have no analyses
+0705c3c Apply recent changes in filenames and locations.
+3560d0b Move sfst compilation from tools/src to libhfst/src/parsers.
+bc49e55 Fix namespace and class names.
+9f356e7 Change file and namespace names.
+3f8d457 Small fixes to sfst compilation.
+c28d2c5 Further separate sfst compilation and command line program.
+0ccd6fe Reorganize sfst compilation into separate compilation units.
+b9b8585 Fix xfst and twolc tests. Use rm -f when removing files that are conditionally created.
+52d3cbf Remove all exe extensions from hfst-twolc and hfst-twolc-loc because they are scripts.
+99d37e6 Remove exe extensions from hfst-twolc and hfst-twolc-loc because they are scripts.
+b9b678e Start separating sfst parser and command line program to their own files. Add a prefix 'sfst' to flex/bison functions and variables.
+9733812 Rename HfstCompiler, hfst-compiler and hfst-scanner to SfstCompiler, sfst-compiler and sfst-scanner.
+ea9fb6b Add a test for hfst.regex using 'definitions'.
+2a7ad84 Add a keyword argument 'definitions' to regex that takes a dictionary mapping transducer names into transducers.
+6c76128 Add regexp operator documentation also to web pages.
+2322ecc Modify regex documentation.
+3155955 Tentatively add documentation about regexp operators.
+77b6444 use ccache if possible, slightly faster travises
+1ab384d Update fst_to_fsa and fsa_to_fst. Support both HfstTransducer and HfstBasicTransducer formats.
+663224d Catch exceptions when compiling pmatch expressions. Add new tests for pmatch functions.
+43e0644 Do not exit on pmatch compiling errors, throw 1 and catch it in command line program.
+0556161 Merge remote-tracking branch 'refs/remotes/origin/master'
+51b811e Small math fix + revert to float, which wasn't causing problems after all
+e1c9af0 Modify fst_to_fsa and fsa_to_fst.
+aaf2f8b Support special symbols and single-character symbols without separator in fsa_to_fst. Update also documentation.
+ebea326 Add simple tests for fst_to_fsa and fsa_to_fst. Also test modifying transitions of an HfstBasicTransducer.
+ecb78d0 Rewrite HfstBasicTransducer's transitions() and state_and_transitions(). Tentatively add an implementation for functions fst_to_fsa and fsa_to_fst.
+a65ca94 Remove HfstBasicTransitions and HfstStates from HfstBasicTransducer and use hfst::implementations::HfstBasicTransitions and hfst::implementations::HfstBasicStates instead.
+4579f7d Give the pythonpath as command line argument for tests that use 'from __future__ import' instead of catenating it to the beginning of file. The import must happen in the beginning of file.
+3dda726 Rename HfstTransitions to HfstBasicTransitions.
+68155b3 Add docstrings and dummy implementations for functions fst_to_fsa and fsa_to_fst.
+4a2814d Document the changes to api.
+3d1a1ce Use the version of HfstBasicTransducer.transitions() returning a reference. Add HfstBasicTransition.set_weight to python api. Add tests for modifying transition weights.
+17e0027 Fix a typo.
+04accec Add help message to copy-for-windows.sh and comments to foma wrappers.
+3688695 Typedef and templatize vector math, reformulate as per article description
+95c022c Add help message.
+1cd8cb8 Add help message.
+dd2f230 Fix vector reading for case where lines don't end with a separator
+5bcb93d Support hfst.compile_xfst_file only for python3.
+4995953 Fix a typo.
+20f39cd Fix copying files on mac as well as pip packaging issues.
+7f60005 Update file instead of deleting it...
+49b0ef9 Tentatively also support python version 2.
+52016b2 Actually copy all files.
+01744fa Omit sdk directory on windows if compiling for python3.5 or higher. Do not redefine _MSC_VER. Do not call subprocess on mac until it works correctly.
+b44f91d Update README.
+f677972 Check if we are compiling with visual studio 14.
+b17eb3d Update PyPI documentation.
+a6ca66b Add missing file.
+410d6ef Get rid of unnecessary libraries.
+f1572e1 Merge branch 'master' of https://github.com/hfst/hfst
+75fcdd9 Fix chaining of functions in example.
+d655229 Minor version bump to combat repo inconsistencies
+91539f0 oops, reset variable
+5566426 add transliterate output mode
+416373d Update documentation.
+b5736dc Add missing file.
+43db07a Move ReplaceType under hfst.xerox_rules. Reorganize some internal functions.
+bc8983e Move python code from swig interface file under module hfst.
+3aff142 Check if readline package is available.
+391f73a Do not keep input to interactive commands in readline history.
+68e1b87 Update description.
+0ff9821 Support apply up and apply down in hfst.start_xfst().
+c687c09 Document return values of compile_xfst_file and compile_lexc_file.
+12da4ae Warn user about missing readline support if --with-readline is not requested. Issue an error if --with-unicode-handler is called as such or with a value of 'yes' or 'no'. Make it possible to disable loading entries from shared object (openfst back-end feature).
+9731e75 Update version number to 3.12.1. Handle links to future and earlier releases so that they are easier to update. Add a README.
+764399e Remove doc/libhfst.py as documentation has been moved under directory doc/hfst/.
+f3df0b9 Add more documentation for XreCompiler. Fix links to installation instructions.
+d2666d6 pre-increment (thanks, cppcheck)
+5712054 Add the script for creating python package. Convert README to dos format.
+4abf93e Update package scripts.
+4888fc6 Add a script for creating package which contains 64-bit python bindings for python3 for mac osx.
+18df468 Add a script fpr creating 64-bit python bindings for python 3.3 and 3.4 for windows.
+4790986 Add README files for python packages for mac and windows.
+3519e4c Add a script for creating the lgpl package.
+0cb9fb5 Add alternative files for making LGPL release of HFST.
+fea6723 (tag: v3.12.1) Add missing files to dist. Do not print termination message when performing tokenize tests.
+65962bf Ready for release 3.12.1.
+77c845d Fix flag elimination bug (reported in issue #342).
 c827bb6 Do not call fsm_destroy until issue with 'double free or corruption' has been fixed.
 3b0e58a Provide a get_current_dir_name() for platforms without one
 b0fb7a6 Merge branch 'master' of https://github.com/hfst/hfst
diff --git a/NEWS b/NEWS
index 6f5ab3d..d054974 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,70 @@
 This file contains all noteworthy changes in HFST development between releases.
 For full listing of changes see ChangeLog.
 
+Noteworthy changes in 3.13.0
+----------------------------
+
+* Numerous improvements to pmatching and tokenization:
+
+  * [].with(X = Y) feature in pmatch This provides support in the pmatch2fst compiler to define "global flags".
+
+  * Add a variable "xerox-composition", default to "on".
+
+  * Consider list symbols (@L..." and "@X...") to be special.
+
+  * Fix runtime handling of contexts and compilation of negative contexts.
+
+  * Make Like() and Unlike() much faster by not sorting the whole vocabulary and only calculating each comparison key once.
+
+  * Keep track of weights along context checking paths and unify weight handling.
+
+  * In blankline-separated mode, keep blanklines in output too.
+
+  * Round weight to zero decimals, non-sci.
+
+  * Make hfst-tokenise usable as a lib; include simple string-to-string function.
+
+  * Use libreadline in hfst-pmatch when available.
+
+  * Cleanup remainder of the pmatch test suite, all the tests now pass.
+
+* Python interface:
+
+  * Support reading several twolc files.
+
+  * Add functions 'compose' and 'cross_product' that take a list of transducers.
+
+  * Allow empty string as input for hfst.fst and hfst.fsa and interpret it as epsilon.
+
+  * Perform fsmbook tests also via python API.
+
+  * Add option --local-hfst to setup.py.
+
+  * Include pre-swig-generated wrappers to pypi source distribution.
+
+* Compilation:
+
+  * Use by default c++11 unordered_map and unordered_set, unless otherwise specified.
+
+  * Add an option --without-c++11 (defaults to 'no') to compile hfst without c++11 support.
+
+  * Require libc++ and osx version >= 10.7 with clang.
+
+* New functions and options:
+
+  * Add function HfstBasicTransducer::remove_final_weight.
+
+  * Add function HfstTransducer::negate() for automata.
+
+  * Add option --restricted-mode (-R) to hfst-xfst.
+
+  * Flag diacritics: support getting a list of operations involved with a particular feature.
+
+  * Allow creating HfstInputStream's from std::istream's.
+
+* Fix issues #341 and #353, make workarounds for issue #358.
+
+
 Noteworthy changes in 3.12.2
 ----------------------------
 
@@ -765,3 +829,4 @@ Noteworthy changes in release 2.1
 ---------------------------------
 
 * hfst-twolc and hfst-compose-intersect understand # like xerox originals
+
diff --git a/README.rst b/README.rst
index 92d89cf..ca31a44 100644
--- a/README.rst
+++ b/README.rst
@@ -29,22 +29,42 @@ Installation packages for Debian and Ubuntu
 
 Debian packages for HFST are distributed via `Apertium project
 <http://apertium.projectjj.com/apt/nightly/pool/main/h/hfst/>`_. This folder
-contains debian packages for HFST API library and tool packages.
+contains debian packages for HFST API library, command line tools and Python bindings.
 The debian packages are experimental; the requirements of debian or ubuntu
 installations are same as main packages. SFST is excluded from the packages
-as it has portability issues with hash_maps and hash_sets. The python packages
-contain binaries for swig-generated Python bindings for HFST.
+as it has portability issues with hash_maps and hash_sets.
+For installation instructions, see our
+`KitWiki pages <https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstDownloads#Installing_HFST_to_Linux>`_.
 
 Binaries for Windows
 --------------------
 
 Binaries for Windows are distributed via `Apertium project
 <http://apertium.projectjj.com/win32/nightly/>`_. This folder contains
-ready-compiled HFST library and command line tools. Performing
+ready-compiled HFST library and command line tools.
+For installation instructions, see our
+`KitWiki pages <https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstDownloads#Installing_HFST_to_Windows>`_.
+Python bindings for Windows are currently available as wheels for 32-bit
+Python versions 2.7, 3.4, 3.5 and 3.6 on our `PyPI page
+<https://pypi.python.org/pypi/hfst>`_.
+Performing
 `installation from the sources`_ is also possible on Windows with MinGW
-and Cygwin. Python bindings for Windows are currently available only for 64-bit
-Python versions 3.3 and 3.4 on our `download page
-<https://hfst.github.io/downloads/index.html>`_.
+and Cygwin, if Python bindings are not needed.
+
+Binaries for Mac OS X
+---------------------
+
+Binaries for OS X are distributed via `Apertium project
+<http://apertium.projectjj.com/osx/nightly/>`_. This folder contains
+ready-compiled HFST library and command line tools.
+For installation instructions, see our
+`KitWiki pages <https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstDownloads#Installing_HFST_to_Mac_OS_X>`_.
+Python bindings for OS X are currently available as wheels for
+Python versions 2.7, 3.4, 3.5 and 3.6 on our `PyPI page
+<https://pypi.python.org/pypi/hfst>`_.
+Performing
+`installation from the sources`_ is also possible on Mac.
+
 
 Installation for Gentoo Linux
 -----------------------------
diff --git a/back-ends/foma/cpp-version/Makefile.am b/back-ends/foma/cpp-version/Makefile.am
new file mode 100644
index 0000000..6d6646f
--- /dev/null
+++ b/back-ends/foma/cpp-version/Makefile.am
@@ -0,0 +1,45 @@
+AUTOMAKE_OPTIONS=std-options
+
+.NOTPARALLEL:
+
+#AM_CPPFLAGS= -Wno-deprecated -std=c99 -D_XOPEN_SOURCE=500
+AM_CPPFLAGS= -Wno-deprecated -D_XOPEN_SOURCE=500 -fpermissive -std=c++11
+
+if WANT_MINGW
+AM_CPPFLAGS += -D__NO_MINGW_LFS
+endif
+
+noinst_LTLIBRARIES = libfoma.la
+libfoma_la_SOURCES = int_stack.cc define.cc determinize.cc apply.cc \
+        rewrite.cc lexcread.cc topsort.cc flags.cc minimize.cc reverse.cc \
+        extract.cc sigma.cc structures.cc constructions.cc \
+        coaccessible.cc io.cc utf8.cc spelling.cc dynarray.cc mem.cc stringhash.cc \
+        trie.cc lex.lexc.cc lex.yy.cc regex.cc
+
+hfst_foma_LDADD = $(top_builddir)/back-ends/foma/libfoma.la
+
+if WANT_READLINE
+hfst_foma_LDFLAGS=-lreadline -lz
+else
+hfst_foma_LDFLAGS=-lz
+endif
+
+if HAVE_TERMCAP
+hfst_foma_LDFLAGS += -ltermcap
+else
+if HAVE_NCURSES
+hfst_foma_LDFLAGS += -lncurses
+else
+if HAVE_CURSES
+hfst_foma_LDFLAGS += -lcurses
+endif
+endif
+endif
+
+if GENERATE_FOMA_WRAPPER
+bin_PROGRAMS=hfst_foma
+hfst_foma_SOURCES=foma.cc stack.cc iface.cc lex.interface.cc lex.ccmatrix.cc
+AM_CPPFLAGS += -DZLIB
+endif
+
+EXTRA_DIST=foma.h fomalibconf.h fomalib.h lexc.h regex.h
diff --git a/back-ends/foma/cpp-version/apply.cc b/back-ends/foma/cpp-version/apply.cc
new file mode 100644
index 0000000..6653e40
--- /dev/null
+++ b/back-ends/foma/cpp-version/apply.cc
@@ -0,0 +1,1498 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2015 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <limits.h>
+#include "foma.h"
+
+#define RANDOM 1
+#define ENUMERATE 2
+#define MATCH 4
+#define UP 8
+#define DOWN 16
+#define LOWER 32
+#define UPPER 64
+#define SPACE 128
+
+#define FAIL 0
+#define SUCCEED 1
+
+#define DEFAULT_OUTSTRING_SIZE 4096
+#define DEFAULT_STACK_SIZE 128
+
+#define APPLY_BINSEARCH_THRESHOLD 10
+
+#define BITMASK(b) (1 << ((b) & 7))
+#define BITSLOT(b) ((b) >> 3)
+#define BITSET(a,b) ((a)[BITSLOT(b)] |= BITMASK(b))
+#define BITCLEAR(a,b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
+#define BITTEST(a,b) ((a)[BITSLOT(b)] & BITMASK(b))
+#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)
+
+
+
+static int apply_append(struct apply_handle *h, int cptr, int sym);
+static char *apply_net(struct apply_handle *h);
+static void apply_create_statemap(struct apply_handle *h,struct fsm *net);
+static void apply_create_sigarray(struct apply_handle *h,struct fsm *net);
+static void apply_create_sigmatch(struct apply_handle *h);
+int apply_match_length(struct apply_handle *h, int symbol);
+static int apply_match_str(struct apply_handle *h,int symbol, int position);
+static void apply_add_flag(struct apply_handle *h,char *name);
+static int apply_check_flag(struct apply_handle *h,int type, char *name, char *value);
+static void apply_clear_flags(struct apply_handle *h);
+void apply_set_iptr(struct apply_handle *h);
+void apply_mark_flagstates(struct apply_handle *h);
+void apply_clear_index(struct apply_handle *h);
+
+static void apply_stack_clear(struct apply_handle *h);
+static int apply_stack_isempty(struct apply_handle *h);
+static void apply_stack_pop (struct apply_handle *h);
+static void apply_stack_push (struct apply_handle *h, int vmark, char *sflagname, char *sflagvalue, int sflagneg);
+static void apply_force_clear_stack(struct apply_handle *h);
+
+
+void apply_set_obey_flags(struct apply_handle *h, int value) {
+    h->obey_flags = value;
+}
+
+void apply_set_show_flags(struct apply_handle *h, int value) {
+    h->show_flags = value;
+}
+
+void apply_set_print_space(struct apply_handle *h, int value) {
+    h->print_space = value;
+    h->space_symbol = xxstrdup(" ");
+}
+
+void apply_set_separator(struct apply_handle *h, char *symbol) {
+    h->separator = xxstrdup(symbol);
+}
+
+void apply_set_epsilon(struct apply_handle *h, char *symbol) {
+    xxfree(h->epsilon_symbol);
+    h->epsilon_symbol = xxstrdup(symbol);
+    (h->sigs+EPSILON)->symbol = h->epsilon_symbol;
+    (h->sigs+EPSILON)->length =  strlen(h->epsilon_symbol);
+}
+
+void apply_set_space_symbol(struct apply_handle *h, char *space) {
+    h->space_symbol = xxstrdup(space);
+    h->print_space = 1;
+}
+
+void apply_set_print_pairs(struct apply_handle *h, int value) {
+    h->print_pairs = value;
+}
+
+static void apply_force_clear_stack(struct apply_handle *h) {
+    /* Make sure stack is empty and marks reset */
+    if (!apply_stack_isempty(h)) {
+	*(h->marks+(h->gstates+h->ptr)->state_no) = 0;
+	while (!apply_stack_isempty(h)) {
+	    apply_stack_pop(h);
+	    *(h->marks+(h->gstates+h->ptr)->state_no) = 0;
+	}
+	h->iterator = 0;
+	h->iterate_old = 0;
+	apply_stack_clear(h);
+    }
+}
+
+char *apply_enumerate(struct apply_handle *h) {
+
+    char *result = NULL;
+    
+    if (h->last_net == NULL || h->last_net->finalcount == 0) {
+	return (NULL);
+    }
+    h->binsearch = 0;
+    if (h->iterator == 0) {
+        h->iterate_old = 0;
+	apply_force_clear_stack(h);
+        result = apply_net(h);
+	if ((h->mode & RANDOM) != RANDOM)
+	  (h->iterator)++;
+    } else {
+        h->iterate_old = 1;
+        result = apply_net(h);
+    }
+    return(result);
+}
+
+char *apply_words(struct apply_handle *h) {
+    h->mode = DOWN + ENUMERATE + LOWER + UPPER;
+    return(apply_enumerate(h));
+}
+
+char *apply_upper_words(struct apply_handle *h) {
+    h->mode = DOWN + ENUMERATE + UPPER;
+    return(apply_enumerate(h));
+}
+
+char *apply_lower_words(struct apply_handle *h) {
+    h->mode = DOWN + ENUMERATE + LOWER;
+    return(apply_enumerate(h));
+}
+
+char *apply_random_words(struct apply_handle *h) {
+    apply_clear_flags(h);
+    h->mode = DOWN + ENUMERATE + LOWER + UPPER + RANDOM;
+    return(apply_enumerate(h));
+}
+
+char *apply_random_lower(struct apply_handle *h) {
+    apply_clear_flags(h);
+    h->mode = DOWN + ENUMERATE + LOWER + RANDOM;
+    return(apply_enumerate(h));
+}
+
+char *apply_random_upper(struct apply_handle *h) {
+    apply_clear_flags(h);
+    h->mode = DOWN + ENUMERATE + UPPER + RANDOM;
+    return(apply_enumerate(h));
+}
+
+/* Frees memory associated with applies */
+void apply_clear(struct apply_handle *h) {
+    struct apply_handle::sigma_trie_arrays *sta, *stap; // TESTING...
+    for (sta = h->sigma_trie_arrays; sta != NULL; ) {
+	stap = sta;
+	xxfree(sta->arr);
+	sta = sta->next;
+	xxfree(stap);
+    }
+    h->sigma_trie_arrays = NULL;
+    if (h->statemap != NULL) {
+        xxfree(h->statemap);
+        h->statemap = NULL;
+    }
+    if (h->numlines != NULL) {
+        xxfree(h->numlines);
+        h->numlines = NULL;
+    }
+    if (h->marks != NULL) {
+        xxfree(h->marks);
+        h->marks = NULL;
+    }
+    if (h->searchstack != NULL) {
+        xxfree(h->searchstack);
+        h->searchstack = NULL;
+    }
+    if (h->sigs != NULL) {
+        xxfree(h->sigs);
+        h->sigs = NULL;
+    }
+    if (h->flag_lookup != NULL) {
+        xxfree(h->flag_lookup);
+        h->flag_lookup = NULL;
+    }
+    if (h->sigmatch_array != NULL) {
+	xxfree(h->sigmatch_array);
+	h->sigmatch_array = NULL;
+    }
+    if (h->flagstates != NULL) {
+	xxfree(h->flagstates);
+	h->flagstates = NULL;
+    }
+    apply_clear_index(h);
+    h->last_net = NULL;
+    h->iterator = 0;
+    xxfree(h->outstring);
+    xxfree(h->separator);
+    xxfree(h->epsilon_symbol);
+    xxfree(h);
+}
+
+char *apply_updown(struct apply_handle *h, char *word) {
+
+    char *result = NULL;
+
+    if (h->last_net == NULL || h->last_net->finalcount == 0)
+        return (NULL);
+    
+    if (word == NULL) {
+        h->iterate_old = 1;
+        result = apply_net(h);
+    }
+    else if (word != NULL) {
+        h->iterate_old = 0;
+        h->instring = word;
+        apply_create_sigmatch(h);
+
+	/* Remove old marks if necessary TODO: only pop marks */
+	apply_force_clear_stack(h);
+        result = apply_net(h);
+    }
+    return(result);
+}
+
+char *apply_down(struct apply_handle *h, char *word) {
+    
+    h->mode = DOWN;
+    if (h->index_in) {
+	h->indexed = 1;
+    } else {
+	h->indexed = 0;
+    }
+    h->binsearch = (h->last_net->arcs_sorted_in == 1) ? 1 : 0;
+    return(apply_updown(h, word));
+}
+
+char *apply_up(struct apply_handle *h, char *word) {
+
+    h->mode = UP;
+    if (h->index_out) {
+	h->indexed = 1;
+    } else {
+	h->indexed = 0;
+    }
+    h->binsearch = (h->last_net->arcs_sorted_out == 1) ? 1 : 0;
+    return(apply_updown(h, word));
+}
+
+struct apply_handle *apply_init(struct fsm *net) {
+    struct apply_handle *h;
+
+    srand((unsigned int) time(NULL));
+    h = (struct apply_handle*)calloc(1,sizeof(struct apply_handle));
+    /* Init */
+
+    h->iterate_old = 0;
+    h->iterator = 0;
+    h->instring = NULL;
+    h->flag_list = NULL;
+    h->flag_lookup = NULL;
+    h->obey_flags = 1;
+    h->show_flags = 0;
+    h->print_space = 0;
+    h->print_pairs = 0;
+    h->separator = xxstrdup(":");
+    h->epsilon_symbol = xxstrdup("0");
+    h->last_net = net;
+    h->outstring = (char*)xxmalloc(sizeof(char)*DEFAULT_OUTSTRING_SIZE);
+    h->outstringtop = DEFAULT_OUTSTRING_SIZE;
+    *(h->outstring) = '\0';
+    h->gstates = net->states;
+    h->gsigma = net->sigma;
+    h->printcount = 1;
+    apply_create_statemap(h, net);
+    h->searchstack = (struct apply_handle::searchstack*)xxmalloc(sizeof(struct apply_handle::searchstack) * DEFAULT_STACK_SIZE);
+    h->apply_stack_top = DEFAULT_STACK_SIZE;
+    apply_stack_clear(h);
+    apply_create_sigarray(h, net);
+    return(h);
+}
+
+int apply_stack_isempty (struct apply_handle *h) {
+    if (h->apply_stack_ptr == 0) {
+	return 1;
+    }
+    return 0;
+}
+
+void apply_stack_clear (struct apply_handle *h) {
+    h->apply_stack_ptr = 0;
+}
+
+void apply_stack_pop (struct apply_handle *h) {
+    struct apply_handle::flag_list *flist;
+    struct apply_handle::searchstack *ss;
+    (h->apply_stack_ptr)--;
+    ss = h->searchstack+h->apply_stack_ptr;
+
+    h->iptr =  ss->iptr;
+    h->ptr  =  ss->offset;
+    h->ipos =  ss->ipos;
+    h->opos =  ss->opos;
+    h->state_has_index = ss->state_has_index;
+    /* Restore mark */
+    *(h->marks+(h->gstates+h->ptr)->state_no) = ss->visitmark;
+
+    if (h->has_flags && ss->flagname != NULL) {
+	/* Restore flag */
+	for (flist = h->flag_list; flist != NULL; flist = flist->next) {
+	    if (strcmp(flist->name, ss->flagname) == 0) {
+		break;
+	    }
+	}
+	if (flist == NULL)
+	    perror("***Nothing to pop\n");
+	flist->value = ss->flagvalue;
+	flist->neg = ss->flagneg;
+    }
+}
+
+static void apply_stack_push (struct apply_handle *h, int vmark, char *sflagname, char *sflagvalue, int sflagneg) {
+    struct apply_handle::searchstack *ss;
+    if (h->apply_stack_ptr == h->apply_stack_top) {
+        h->searchstack = (struct apply_handle::searchstack*)xxrealloc(h->searchstack, sizeof(struct apply_handle::searchstack)* ((h->apply_stack_top)*2));
+	if (h->searchstack == NULL) {
+	  perror("Apply stack full!!!\n");
+	  exit(0);
+	}
+	h->apply_stack_top *= 2;
+    }
+    ss = h->searchstack+h->apply_stack_ptr;
+    ss->offset     = h->curr_ptr;
+    ss->ipos       = h->ipos;
+    ss->opos       = h->opos;
+    ss->visitmark  = vmark;
+    ss->iptr       = h->iptr;
+    ss->state_has_index = h->state_has_index;
+    if (h->has_flags) {
+	ss->flagname   = sflagname;
+	ss->flagvalue  = sflagvalue;
+	ss->flagneg    = sflagneg;
+    }
+    (h->apply_stack_ptr)++;
+}
+
+void apply_reset_enumerator(struct apply_handle *h) {
+    int statecount, i;
+    statecount = h->last_net->statecount;
+    for (i=0; i < statecount; i++) {
+	*(h->marks+i) = 0;
+    }
+    h->iterator = 0;
+    h->iterate_old = 0;
+}
+
+void apply_clear_index_list(struct apply_handle *h, struct apply_handle::apply_state_index **index) {
+    int i, j, statecount;
+    struct apply_handle::apply_state_index *iptr, *iptr_tmp, *iptr_zero;
+    if (index == NULL)
+	return;
+    statecount = h->last_net->statecount;
+    for (i = 0; i < statecount; i++) {
+	iptr = *(index+i);
+	if (iptr == NULL) {
+	    continue;
+	}
+	iptr_zero = *(index+i);
+	for (j = h->sigma_size - 1 ; j >= 0; j--) { /* Make sure to not free the list in EPSILON    */
+	    iptr = *(index+i) + j;                  /* as the other states lists' tails point to it */
+	    for (iptr = iptr->next ; iptr != NULL && iptr != iptr_zero; iptr = iptr_tmp) {
+		iptr_tmp = iptr->next;
+		xxfree(iptr);
+	    }
+	}
+	xxfree(*(index+i));
+    }
+}
+
+void apply_clear_index(struct apply_handle *h) {
+    if (h->index_in) {
+	apply_clear_index_list(h, h->index_in);
+	xxfree(h->index_in);
+	h->index_in = NULL;
+    }
+    if (h->index_out) {
+	apply_clear_index_list(h, h->index_out);
+	xxfree(h->index_out);
+	h->index_out = NULL;
+    }
+}
+
+void apply_index(struct apply_handle *h, int inout, int densitycutoff, int mem_limit, int flags_only) {
+#ifdef ORIGINAL
+    struct fsm_state *fsm;
+#else
+    // variable initialization needed for cl.exe compiler
+    struct fsm_state *fsm = h->gstates;
+#endif
+    unsigned int cnt = 0;
+    int i, j, maxtrans, numtrans, laststate, sym;
+#ifdef ORIGINAL
+    fsm = h->gstates;
+#else
+    // variable already initialized
+#endif
+
+    struct apply_handle::apply_state_index **indexptr, *iptr, *tempiptr;
+
+    struct pre_index {
+	int state_no;
+	struct pre_index *next;
+    } *pre_index, *tp, *tpp;
+    if (flags_only && !h->has_flags) {
+	return;
+    }
+    /* get numtrans */
+    for (i=0, laststate = 0, maxtrans = 0, numtrans = 0; (fsm+i)->state_no != -1; i++) {
+	if ((fsm+i)->state_no != laststate) {
+	    maxtrans = numtrans > maxtrans ? numtrans : maxtrans;
+	    numtrans = 0;
+	}
+	if ((fsm+i)->target != -1) {
+	    numtrans++;
+	}
+	laststate = (fsm+i)->state_no;
+    }
+
+    pre_index = (struct pre_index*)xxcalloc(maxtrans+1, sizeof(struct pre_index));
+    for (i = 0; i <= maxtrans; i++) {
+	(pre_index+i)->state_no = -1;
+    }
+
+    /* We create an array of states, indexed by how many transitions they have */
+    /* so that later, we can traverse them in order densest first, in case we  */
+    /* only want to index to some predefined maximum memory usage.             */
+
+    for (i = 0, laststate = 0, maxtrans = 0, numtrans = 0; (fsm+i)->state_no != -1; i++) {
+	if ((fsm+i)->state_no != laststate) {
+	    if ((pre_index+numtrans)->state_no == -1) {
+		(pre_index+numtrans)->state_no = laststate;
+	    } else {
+	        tp = (struct pre_index*)xxcalloc(1, sizeof(struct pre_index));
+		tp->state_no = laststate;
+		tp->next = (pre_index+numtrans)->next;
+		(pre_index+numtrans)->next = tp;
+	    }
+	    maxtrans = numtrans > maxtrans ? numtrans : maxtrans;
+	    numtrans = 0;
+	}
+	if ((fsm+i)->target != -1) {
+	    numtrans++;
+	}
+	laststate = (fsm+i)->state_no;
+    }
+    indexptr = NULL;
+    cnt += round_up_to_power_of_two(h->last_net->statecount*sizeof(struct apply_state_index *));
+
+    if (cnt > mem_limit) {
+	cnt -= round_up_to_power_of_two(h->last_net->statecount*sizeof(struct apply_state_index *));
+	goto memlimitnoindex;
+    }
+
+    indexptr = (struct apply_handle::apply_state_index**)xxcalloc(h->last_net->statecount, sizeof(struct apply_handle::apply_state_index *));
+
+    if (h->has_flags && flags_only) {
+	/* Mark states that have flags */
+	if (!(h->flagstates)) {
+	    apply_mark_flagstates(h);
+	}
+    }
+
+    for (i = maxtrans; i >= 0; i--) {
+	for (tp = pre_index+i; tp != NULL; tp = tp->next) {
+	    if (tp->state_no >= 0) {
+		if (i < densitycutoff) {
+		    if (!(h->has_flags && flags_only && BITTEST(h->flagstates, tp->state_no))) {
+			continue;
+		    }
+		}
+		cnt += round_up_to_power_of_two(h->sigma_size*sizeof(struct apply_handle::apply_state_index));
+		if (cnt > mem_limit) {
+		    cnt -= round_up_to_power_of_two(h->sigma_size*sizeof(struct apply_handle::apply_state_index));
+		    goto memlimit;
+		}
+		*(indexptr + tp->state_no) = (struct apply_handle::apply_state_index*)xxmalloc(h->sigma_size*sizeof(struct apply_handle::apply_state_index));
+
+		/* We make the tail of all index linked lists point to the index  */
+		/* for EPSILON, so that we automatically when EPSILON transitions */
+		/* also when traversing an index.                                 */
+
+		for (j = 0; j < h->sigma_size; j++) {
+		    (*(indexptr + tp->state_no) + j)->fsmptr = -1;
+		    if (j == EPSILON)
+			(*(indexptr + tp->state_no) + j)->next = NULL;
+		    else
+			(*(indexptr + tp->state_no) + j)->next = (*(indexptr + tp->state_no)); /* all tails point to epsilon */
+		}
+	    }
+	}
+    }
+
+ memlimit:
+
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+	iptr = *(indexptr + (fsm+i)->state_no);
+	if (iptr == NULL || (fsm+i)->target == -1) {
+	    continue;
+	}
+	sym = inout == APPLY_INDEX_INPUT ? (fsm+i)->in : (fsm+i)->out;
+
+	if (h->has_flags && (h->flag_lookup+sym)->type) {
+	    sym = EPSILON;
+	}
+	if (sym == UNKNOWN) {  /* We make the index of UNKNOWN point to IDENTITY */
+	    sym = IDENTITY;    /* since these are really the same symbol         */
+	}
+	if ((iptr+sym)->fsmptr == -1) {
+	    (iptr+sym)->fsmptr = i;
+	} else {
+	    cnt += round_up_to_power_of_two(sizeof(struct apply_handle::apply_state_index));
+	    tempiptr = (struct apply_handle::apply_state_index*)xxcalloc(1, sizeof(struct apply_handle::apply_state_index));
+
+	    tempiptr->next = (iptr+sym)->next;
+	    tempiptr->fsmptr =  i;
+	    (iptr+sym)->next = tempiptr;
+	}
+    }
+
+    /* Free preindex */
+
+ memlimitnoindex:
+
+    for (i = maxtrans; i >= 0; i--) {
+	for (tp = (pre_index+i)->next; tp != NULL; tp = tpp) {
+	    tpp = tp->next;
+	    xxfree(tp);
+	}
+    }
+    xxfree(pre_index);
+
+    if (inout == APPLY_INDEX_INPUT) {
+	h->index_in = indexptr;
+    } else {
+	h->index_out = indexptr;
+    }
+}
+
+int apply_binarysearch(struct apply_handle *h) {
+    int thisstate, nextsym, seeksym, thisptr, lastptr, midptr;
+
+    thisptr = h->curr_ptr = h->ptr;
+    nextsym  = (((h->mode) & DOWN) == DOWN) ? (h->gstates+h->curr_ptr)->in  : (h->gstates+h->curr_ptr)->out;
+    if (nextsym == EPSILON)
+	return 1;
+    if (nextsym == -1)
+	return 0;
+    if (h->ipos >= h->current_instring_length) {
+	return 0;
+    }
+    seeksym = (h->sigmatch_array+h->ipos)->signumber;
+    if (seeksym == nextsym || (nextsym == UNKNOWN && seeksym == IDENTITY))
+	return 1;
+
+    thisstate = (h->gstates+thisptr)->state_no;
+    lastptr = *(h->statemap+thisstate)+*(h->numlines+thisstate)-1;
+    thisptr++;
+
+    if (seeksym == IDENTITY || lastptr - thisptr < APPLY_BINSEARCH_THRESHOLD) {
+	for ( ; thisptr <= lastptr; thisptr++) {
+	    nextsym = (((h->mode) & DOWN) == DOWN) ? (h->gstates+thisptr)->in : (h->gstates+thisptr)->out;
+	    if ((nextsym == seeksym) || (nextsym == UNKNOWN && seeksym == IDENTITY)) {
+		h->curr_ptr = thisptr;
+		return 1;
+	    }
+	    if (nextsym > seeksym || nextsym == -1) {
+		return 0;
+	    }
+	}
+	return 0;
+    }
+     
+    for (;;)  {
+	if (thisptr > lastptr) { return 0; }
+	midptr = (thisptr+lastptr)/2;
+	nextsym = (((h->mode) & DOWN) == DOWN) ? (h->gstates+midptr)->in : (h->gstates+midptr)->out;
+	if (seeksym < nextsym) {
+	    lastptr = midptr - 1;
+	    continue;
+	} else if (seeksym > nextsym) {
+	    thisptr = midptr + 1;
+	    continue;
+	} else {
+
+	    while (((((h->mode) & DOWN) == DOWN) ? (h->gstates+(midptr-1))->in : (h->gstates+(midptr-1))->out) == seeksym) {
+		midptr--; /* Find first match in case of ties */
+	    }
+	    h->curr_ptr = midptr;
+	    return 1;
+	}
+    }
+}
+
+int apply_follow_next_arc(struct apply_handle *h) {
+    char *fname, *fvalue;
+    int eatupi, eatupo, symin, symout, fneg;
+    int vcount, marksource, marktarget;
+    
+    /* Here we follow three possible search strategies:        */
+    /* (1) if the state in question has an index, we use that  */
+    /* (2) if the state is binary searchable, we use that      */
+    /* (3) otherwise we traverse arc-by-arc                    */
+    /*     Condition (2) needs arcs to be sorted in the proper */
+    /*     direction, and requires that the state be flag-free */
+    /*     For those states that aren't flag-free, (3) is used */
+
+    if (h->state_has_index) {
+	for ( ; h->iptr != NULL && h->iptr->fsmptr != -1; ) {
+
+	    h->ptr = h->curr_ptr = h->iptr->fsmptr;
+	    if (((h->mode) & DOWN) == DOWN) {
+		symin = (h->gstates+h->curr_ptr)->in;
+		symout = (h->gstates+h->curr_ptr)->out;
+	    } else {
+		symin = (h->gstates+h->curr_ptr)->out;
+		symout = (h->gstates+h->curr_ptr)->in;
+	    }
+	    
+	    marksource = *(h->marks+(h->gstates+h->ptr)->state_no);
+	    marktarget = *(h->marks+(h->gstates+(*(h->statemap+(h->gstates+h->curr_ptr)->target)))->state_no);
+	    eatupi = apply_match_length(h, symin);
+	    if (!(eatupi == -1 || -1-(h->ipos)-eatupi == marktarget)) {     /* input 2x EPSILON loop check */
+		if ((eatupi = apply_match_str(h, symin, h->ipos)) != -1) {
+		    eatupo = apply_append(h, h->curr_ptr, symout);
+		    if (h->obey_flags && h->has_flags && ((h->flag_lookup+symin)->type & (FLAG_UNIFY|FLAG_CLEAR|FLAG_POSITIVE|FLAG_NEGATIVE))) {
+			fname = (h->flag_lookup+symin)->name;
+			fvalue = h->oldflagvalue;
+			fneg = h->oldflagneg;
+		    } else {
+			fname = fvalue = NULL;
+			fneg = 0;
+		    }
+		    /* Push old position */
+		    apply_stack_push(h, marksource, fname, fvalue, fneg);
+		    h->ptr = *(h->statemap+(h->gstates+h->curr_ptr)->target);
+		    h->ipos += eatupi;
+		    h->opos += eatupo;
+		    apply_set_iptr(h);
+		    return 1;
+		}
+	    }
+	    h->iptr = h->iptr->next;
+	}
+	return 0;
+    } else if ((h->binsearch && !(h->has_flags)) || (h->binsearch && !(BITTEST(h->flagstates, (h->gstates+h->ptr)->state_no)))) {
+	for (;;) {
+	    if (apply_binarysearch(h)) {
+		if (((h->mode) & DOWN) == DOWN) {
+		    symin = (h->gstates+h->curr_ptr)->in;
+		    symout = (h->gstates+h->curr_ptr)->out;
+		} else {
+		    symin = (h->gstates+h->curr_ptr)->out;
+		    symout = (h->gstates+h->curr_ptr)->in;
+		}
+		
+		marksource = *(h->marks+(h->gstates+h->ptr)->state_no);
+		marktarget = *(h->marks+(h->gstates+(*(h->statemap+(h->gstates+h->curr_ptr)->target)))->state_no);
+		
+		eatupi = apply_match_length(h, symin);
+		if (eatupi != -1 && -1-(h->ipos)-eatupi != marktarget) {
+		    if ((eatupi = apply_match_str(h, symin, h->ipos)) != -1) {
+			eatupo = apply_append(h, h->curr_ptr, symout);
+			
+			/* Push old position */
+			apply_stack_push(h, marksource, NULL, NULL, 0);
+			
+			/* Follow arc */
+			h->ptr = *(h->statemap+(h->gstates+h->curr_ptr)->target);
+			h->ipos += eatupi;
+			h->opos += eatupo;
+			apply_set_iptr(h);
+			return 1;
+		    }
+		}
+		if ((h->gstates+h->curr_ptr)->state_no == (h->gstates+h->curr_ptr+1)->state_no) {
+		    h->curr_ptr++;
+		    h->ptr = h->curr_ptr;
+		    if ((h->gstates+h->curr_ptr)-> target == -1) {
+			return 0;
+		    }
+		    continue;
+		}
+	    }
+	    return 0;
+	}
+    } else {
+	for (h->curr_ptr = h->ptr; (h->gstates+h->curr_ptr)->state_no == (h->gstates+h->ptr)->state_no && (h->gstates+h->curr_ptr)-> in != -1; (h->curr_ptr)++) {
+	    
+	    /* Select one random arc to follow out of all outgoing arcs */
+	    if ((h->mode & RANDOM) == RANDOM) {
+		vcount = 0;
+		for (h->curr_ptr = h->ptr;  (h->gstates+h->curr_ptr)->state_no == (h->gstates+h->ptr)->state_no && (h->gstates+h->curr_ptr)-> in != -1; (h->curr_ptr)++) {
+		    vcount++;
+		}
+		if (vcount > 0) {
+		    h->curr_ptr = h->ptr + (rand() % vcount);
+		} else {
+		    h->curr_ptr = h->ptr;
+		}
+	    }
+	    
+	    if (((h->mode) & DOWN) == DOWN) {
+		symin = (h->gstates+h->curr_ptr)->in;
+		symout = (h->gstates+h->curr_ptr)->out;
+	    } else {
+		symin = (h->gstates+h->curr_ptr)->out;
+		symout = (h->gstates+h->curr_ptr)->in;
+	    }
+	    
+	    marksource = *(h->marks+(h->gstates+h->ptr)->state_no);
+	    marktarget = *(h->marks+(h->gstates+(*(h->statemap+(h->gstates+h->curr_ptr)->target)))->state_no);
+
+	    eatupi = apply_match_length(h, symin);
+
+	    if (eatupi == -1 || -1-(h->ipos)-eatupi == marktarget) { continue; } /* loop check */
+	    if ((eatupi = apply_match_str(h, symin, h->ipos)) != -1) {
+		eatupo = apply_append(h, h->curr_ptr, symout);
+		if (h->obey_flags && h->has_flags && ((h->flag_lookup+symin)->type & (FLAG_UNIFY|FLAG_CLEAR|FLAG_POSITIVE|FLAG_NEGATIVE))) {
+		    
+		    fname = (h->flag_lookup+symin)->name;
+		    fvalue = h->oldflagvalue;
+		    fneg = h->oldflagneg;
+		} else {
+		    fname = fvalue = NULL;
+		    fneg = 0;
+		}
+		
+		/* Push old position */
+		apply_stack_push(h, marksource, fname, fvalue, fneg);
+		
+		/* Follow arc */
+		h->ptr = *(h->statemap+(h->gstates+h->curr_ptr)->target);
+		h->ipos += eatupi;
+		h->opos += eatupo;
+		apply_set_iptr(h);
+		return(1);
+	    }
+	}
+	return(0);
+    }
+}
+
+char *apply_return_string(struct apply_handle *h) {
+    /* Stick a 0 to endpos to avoid getting old accumulated gunk strings printed */
+    *(h->outstring+h->opos) = '\0';
+    if (((h->mode) & RANDOM) == RANDOM) {
+	/* To end or not to end */
+	if (!(rand() % 2)) {
+	    apply_stack_clear(h);
+	    h->iterator = 0;
+	    h->iterate_old = 0;
+	    return(h->outstring);
+	}
+    } else {
+	return(h->outstring);
+    }
+    return(NULL);
+}
+
+void apply_mark_state(struct apply_handle *h) {
+
+    /* This controls the how epsilon-loops are traversed.  Such loops can    */
+    /* only be followed once to reach a state already visited in the DFS.    */
+    /* This requires that we store the number of input symbols consumed      */
+    /* whenever we enter a new state.  If we enter the same state twice      */
+    /* with the same number of input symbols consumed, we abandon the search */
+    /* for that branch. Flags are epsilons from this point of view.          */
+    /* The encoding of h->marks is:                                          */
+    /* 0 = unseen, +ipos = seen at ipos, -ipos = seen second time at ipos    */
+
+    if ((h->mode & RANDOM) != RANDOM) {
+	if (*(h->marks+(h->gstates+h->ptr)->state_no) == h->ipos+1) {
+	    *(h->marks+(h->gstates+h->ptr)->state_no) = -(h->ipos+1);
+	} else {
+	    *(h->marks+(h->gstates+h->ptr)->state_no) = h->ipos+1;
+	}
+    }
+}
+
+void apply_skip_this_arc(struct apply_handle *h) {
+    /* If we have index ptr */
+    if (h->iptr) {
+	h->ptr = h->iptr->fsmptr;
+	h->iptr = h->iptr->next;
+	/* Otherwise */
+    } else {
+	(h->ptr)++;
+    }
+}
+
+int apply_at_last_arc(struct apply_handle *h) {
+    int seeksym, nextsym;
+    if (h->state_has_index) {
+	if (h->iptr->next == NULL || h->iptr->next->fsmptr == -1) {
+	    return 1;
+	}
+    } else {
+	if  ((h->binsearch && !(h->has_flags)) || (h->binsearch && !(BITTEST(h->flagstates, (h->gstates+h->ptr)->state_no)))) {
+	    if ((h->gstates+h->ptr)->state_no != (h->gstates+h->ptr+1)->state_no) {
+		return 1;
+	    }
+	    seeksym = (h->sigmatch_array+h->ipos)->signumber;
+	    nextsym  = (((h->mode) & DOWN) == DOWN) ? (h->gstates+h->ptr)->in  : (h->gstates+h->ptr)->out;
+	    if (nextsym == -1 || seeksym < nextsym) {
+		return 1;
+	    }
+	} else {
+	    if ((h->gstates+h->ptr)->state_no != (h->gstates+h->ptr+1)->state_no) {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+/* map h->ptr (line pointer) to h->iptr (index pointer) */
+void apply_set_iptr(struct apply_handle *h) {
+    struct apply_handle::apply_state_index **idx, *sidx;
+    int stateno, seeksym;
+    /* Check if state has index */
+    if ((idx = ((h->mode) & DOWN) == DOWN ? (h->index_in) : (h->index_out)) == NULL) {
+	return;
+    }
+ 
+    h->iptr = NULL;
+    h->state_has_index = 0;
+    stateno = (h->gstates+h->ptr)->state_no;
+    if (stateno < 0) {
+	return;
+    }
+   
+    sidx = *(idx + stateno);
+    if (sidx == NULL) { return; }
+    seeksym = (h->sigmatch_array+h->ipos)->signumber;
+    h->state_has_index = 1;
+    sidx = sidx + seeksym;
+    if (sidx->fsmptr == -1) {
+	if (sidx->next == NULL) {
+	    return;
+	} else {
+	    sidx = sidx->next;
+	}
+    }
+    h->iptr = sidx;
+    if (sidx->fsmptr == -1) {
+	h->iptr = NULL;
+    }
+    h->state_has_index = 1;
+}
+
+char *apply_net(struct apply_handle *h) {
+
+/*     We perform a basic DFS on the graph, with two minor complications:       */
+
+/*     1. We keep a mark for each state which indicates how many input symbols  */
+/*        we had consumed the last time we entered that state on the current    */
+/*        "run."  If we reach a state seen twice without consuming input, we    */
+/*        terminate that branch of the search.                                  */
+/*        As we pop a position, we also unmark the state we came from.          */
+ 
+/*     2. If the graph has flags, we push the previous flag value when          */
+/*        traversing a flag-modifying arc (P,U,N, or C).  This is because a     */
+/*        flag may have been set during the previous "run" and may not apply.   */
+/*        Since we're doing a DFS, we can be sure to return to the previous     */
+/*        global flag state by just remembering that last flag change.          */
+
+/*     3. The whole system needs to work as an iterator, meaning we need to     */
+/*        store the global state of the search so we can resume it later to     */
+/*        to yield more possible output words with the same input string.       */
+
+    char *returnstring;
+
+    if (h->iterate_old == 1) {     /* If called with NULL as the input word, this will be set */
+        goto resume;
+    }
+
+    h->iptr = NULL; h->ptr = 0; h->ipos = 0; h->opos = 0;
+    apply_set_iptr(h);
+
+    apply_stack_clear(h);
+
+    if (h->has_flags) {
+	apply_clear_flags(h);
+    }
+    
+    /* "The use of four-letter words like goto can occasionally be justified */
+    /*  even in the best of company." Knuth (1974).                          */
+
+    goto L2;
+
+    while(!apply_stack_isempty(h)) {
+	apply_stack_pop(h);
+	/* If last line was popped */
+	if (apply_at_last_arc(h)) {
+	    *(h->marks+(h->gstates+h->ptr)->state_no) = 0; /* Unmark   */
+	    continue;                                      /* pop next */
+	}
+	apply_skip_this_arc(h);                            /* skip old pushed arc */
+    L1:
+	if (!apply_follow_next_arc(h)) {
+	    *(h->marks+(h->gstates+h->ptr)->state_no) = 0; /* Unmark   */
+	    continue;                                      /* pop next */
+	}
+    L2:
+	/* Print accumulated string upon entry to state */
+	if ((h->gstates+h->ptr)->final_state == 1 && (h->ipos == h->current_instring_length || ((h->mode) & ENUMERATE) == ENUMERATE)) {
+	    if ((returnstring = (apply_return_string(h))) != NULL) {
+		return(returnstring);
+	    }
+	}
+
+    resume:
+       	apply_mark_state(h);  /* Mark upon arrival to new state */
+	goto L1;
+    }
+    if ((h->mode & RANDOM) == RANDOM) {
+          apply_stack_clear(h);
+          h->iterator = 0;
+          h->iterate_old = 0;
+          return(h->outstring);
+    }
+    apply_stack_clear(h);
+    return NULL;
+}
+
+int apply_append(struct apply_handle *h, int cptr, int sym) {
+
+    char *astring, *bstring, *pstring;
+    int symin, symout, len, alen, blen, idlen;
+    
+    symin = (h->gstates+cptr)->in;
+    symout = (h->gstates+cptr)->out;
+    astring = ((h->sigs)+symin)->symbol;
+    alen =  ((h->sigs)+symin)->length;
+    bstring = ((h->sigs)+symout)->symbol;
+    blen =  ((h->sigs)+symout)->length;
+    
+    while (alen + blen + h->opos + 2 + strlen(h->separator) >= h->outstringtop) {
+	//    while (alen + blen + h->opos + 3 >= h->outstringtop) {
+        h->outstring = (char*)xxrealloc(h->outstring, sizeof(char) * ((h->outstringtop) * 2));
+	(h->outstringtop) *= 2;
+    }
+    
+    if ((h->has_flags) && !h->show_flags && (h->flag_lookup+symin)->type) {
+	astring = ""; alen = 0;
+    }
+    if (h->has_flags && !h->show_flags && (h->flag_lookup+symout)->type) {
+	bstring = ""; blen = 0;
+    }
+    if (((h->mode) & ENUMERATE) == ENUMERATE) {
+	/* Print both sides separated by colon */
+	/* if we're printing "words" */
+	if (((h->mode) & (UPPER | LOWER)) == (UPPER|LOWER)) {
+	    
+	    if (astring == bstring) {
+		strcpy(h->outstring+h->opos, astring);
+		len = alen;
+	    } else {
+		strcpy(h->outstring+h->opos, astring);
+		//		strcpy(h->outstring+h->opos+alen,":");
+		strcpy(h->outstring+h->opos+alen,h->separator);
+		//strcpy(h->outstring+h->opos+alen+1,bstring);
+		strcpy(h->outstring+h->opos+alen+strlen(h->separator),bstring);
+		//		len = alen+blen+1;
+		len = alen+blen+strlen(h->separator);
+	    }
+	}
+	
+	/* Print one side only */
+	if (((h->mode) & (UPPER|LOWER)) != (UPPER|LOWER)) {
+	    
+	    if (symin == EPSILON) {
+		astring = ""; alen = 0;
+	    }
+	    if (symout == EPSILON) {
+		bstring = ""; blen = 0;
+	    }
+	    if (((h->mode) & (UPPER|LOWER)) == UPPER) {
+		pstring = astring;
+		len = alen;
+	    } else {
+		pstring = bstring;
+		len = blen;
+	    }
+	    //strcpy(h->outstring+h->opos, pstring);
+	    memcpy(h->outstring+h->opos, pstring, len);
+	}
+    }
+    if (((h->mode) & ENUMERATE) != ENUMERATE) {
+	/* Print pairs is ON and symbols are different */
+	if (h->print_pairs && (symin != symout)) {
+
+	    if (symin == UNKNOWN && ((h->mode) & DOWN) == DOWN)
+		strncpy(astring, h->instring+h->ipos, 1);
+	    if (symout == UNKNOWN && ((h->mode) & UP) == UP)
+		strncpy(bstring, h->instring+h->ipos, 1);
+	    strcpy(h->outstring+h->opos, "<");
+	    strcpy(h->outstring+h->opos+1, astring);
+	    //strcpy(h->outstring+h->opos+alen+1,":");
+	    strcpy(h->outstring+h->opos+alen+1,h->separator);
+	    //strcpy(h->outstring+h->opos+alen+2,bstring);
+	    strcpy(h->outstring+h->opos+alen+1+strlen(h->separator), bstring);
+	    //strcpy(h->outstring+h->opos+alen+blen+2,">");
+	    strcpy(h->outstring+h->opos+alen+blen+1+strlen(h->separator),">");
+	    //len = alen+blen+3;
+	    len = alen+blen+2+strlen(h->separator);
+	}
+
+	else if (sym == IDENTITY) {
+	    /* Apply up/down */
+	    //idlen = utf8skip(h->instring+h->ipos)+1;
+	    idlen = (h->sigmatch_array+h->ipos)->consumes; // here
+	    strncpy(h->outstring+h->opos, h->instring+h->ipos, idlen);
+	    strncpy(h->outstring+h->opos+idlen,"", 1);
+	    len = idlen;
+	} else if (sym == EPSILON) {
+	    return(0);
+	} else {
+	    if (((h->mode) & DOWN) == DOWN) {
+		pstring = bstring;
+		len = blen;
+	    } else {
+		pstring = astring;
+		len = alen;
+	    }
+	    memcpy(h->outstring+h->opos, pstring, len);
+	}
+    }
+    if (h->print_space && len > 0) {
+	strcpy(h->outstring+h->opos+len, h->space_symbol);
+	len++;
+    }
+    return(len);
+}
+
+int apply_match_length(struct apply_handle *h, int symbol) {
+    if (symbol == EPSILON) {
+	return 0;
+    }
+    if (h->has_flags && (h->flag_lookup+symbol)->type) {
+	return 0;
+    }
+    if (((h->mode) & ENUMERATE) == ENUMERATE) {
+	return 0;
+    }
+    if (h->ipos >= h->current_instring_length) {
+	return -1;
+    }
+    if ((h->sigmatch_array+(h->ipos))->signumber == symbol) {
+	    return((h->sigmatch_array+(h->ipos))->consumes);
+    }
+    if ((symbol == IDENTITY) || (symbol == UNKNOWN)) {
+	if ((h->sigmatch_array+h->ipos)->signumber == IDENTITY) {
+	    return((h->sigmatch_array+(h->ipos))->consumes);
+	}
+    }
+    return -1;
+}
+
+/* Match a symbol from sigma against the current position in string */
+/* Return the number of symbols consumed in input string            */
+/* For flags, we consume 0 symbols of the input string, naturally   */
+
+int apply_match_str(struct apply_handle *h, int symbol, int position) {
+    if (((h->mode) & ENUMERATE) == ENUMERATE) {
+	if (h->has_flags && (h->flag_lookup+symbol)->type) {
+	    if (!h->obey_flags) {
+		return 0;
+	    }
+	    if (apply_check_flag(h,(h->flag_lookup+symbol)->type, (h->flag_lookup+symbol)->name, (h->flag_lookup+symbol)->value) == SUCCEED) {
+		return 0;
+	    } else {
+		return -1;
+	    }
+	}
+	return(0);
+    }
+
+
+    if (symbol == EPSILON) {
+	return 0;
+    }
+    
+    /* If symbol is a flag, we need to check consistency */
+    if (h->has_flags && (h->flag_lookup+symbol)->type) {
+	if (!h->obey_flags) {
+	    return 0;
+	}
+	if (apply_check_flag(h,(h->flag_lookup+symbol)->type, (h->flag_lookup+symbol)->name, (h->flag_lookup+symbol)->value) == SUCCEED) {
+	    return 0;
+	} else {
+	    return -1;
+	}
+    }
+    
+    if (position >= h->current_instring_length) {
+	return -1;
+    }
+    if ((h->sigmatch_array+position)->signumber == symbol) {
+	return((h->sigmatch_array+position)->consumes);
+    }
+    if ((symbol == IDENTITY) || (symbol == UNKNOWN)) {
+	if ((h->sigmatch_array+position)->signumber == IDENTITY) {
+	    return((h->sigmatch_array+position)->consumes);
+	}
+    }
+    return -1;
+}
+
+void apply_create_statemap(struct apply_handle *h, struct fsm *net) {
+    int i;
+    struct fsm_state *fsm;
+    fsm = net->states;
+    h->statemap = (int*)xxmalloc(sizeof(int)*net->statecount);
+    h->marks = (int*)xxmalloc(sizeof(int)*net->statecount);
+    h->numlines = (int*)xxmalloc(sizeof(int)*net->statecount);
+
+    for (i=0; i < net->statecount; i++) {
+	*(h->numlines+i) = 0;  /* Only needed in binary search */
+	*(h->statemap+i) = -1;
+	*(h->marks+i) = 0;
+    }
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+	*(h->numlines+(fsm+i)->state_no) = *(h->numlines+(fsm+i)->state_no)+1;
+	if (*(h->statemap+(fsm+i)->state_no) == -1) {
+	    *(h->statemap+(fsm+i)->state_no) = i;
+	}
+    }
+}
+
+void apply_add_sigma_trie(struct apply_handle *h, int number, char *symbol, int len) {
+
+    /* Create a trie of sigma symbols (prefixes) so we can    */
+    /* quickly (in O(n)) tokenize an arbitrary string into    */
+    /* integer sequences representing symbols, using longest- */
+    /* leftmost factorization.                                */
+
+    int i;
+    struct apply_handle::sigma_trie *st;
+    struct apply_handle::sigma_trie_arrays *sta;
+
+    st = h->sigma_trie;
+    for (i = 0; i < len; i++) {
+	st = st+(unsigned char)*(symbol+i);
+	if (i == (len-1)) {
+	    st->signum = number;
+	} else {
+	    if (st->next == NULL) {
+	        st->next = (struct apply_handle::sigma_trie*)xxcalloc(256,sizeof(struct apply_handle::sigma_trie));
+		st = st->next;
+		/* store these arrays to free them later */
+		sta = (struct apply_handle::sigma_trie_arrays*)xxmalloc(sizeof(struct apply_handle::sigma_trie_arrays));
+		sta->arr = st;
+		sta->next = h->sigma_trie_arrays;
+		h->sigma_trie_arrays = sta;
+	    } else {
+		st = st->next;
+	    }
+	}
+    }
+}
+
+void apply_mark_flagstates(struct apply_handle *h) {
+    int i;
+    struct fsm_state *fsm;
+
+    /* Create bitarray with those states that have a flag symbol on an arc */
+    /* This is needed to decide whether we can perform a binary search.    */
+
+    if (!h->has_flags || h->flag_lookup == NULL) {
+	return;
+    }
+    if (h->flagstates) {
+	xxfree(h->flagstates);
+    }
+    h->flagstates = (uint8_t*)xxcalloc(BITNSLOTS(h->last_net->statecount), sizeof(uint8_t));
+    fsm = h->last_net->states;
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+	if ((fsm+i)->target == -1) {
+	    continue;
+	}
+	if ((h->flag_lookup+(fsm+i)->in)->type) {
+	    BITSET(h->flagstates,(fsm+i)->state_no);
+	}
+	if ((h->flag_lookup+(fsm+i)->out)->type) {
+	    BITSET(h->flagstates,(fsm+i)->state_no);
+	}
+    }
+}
+
+void apply_create_sigarray(struct apply_handle *h, struct fsm *net) {
+    struct sigma *sig;
+    int i, maxsigma;
+    
+    maxsigma = sigma_max(net->sigma);
+    h->sigma_size = maxsigma+1;
+    // Default size created at init, resized later if necessary
+    h->sigmatch_array = (struct apply_handle::sigmatch_array*)xxcalloc(1024,sizeof(struct apply_handle::sigmatch_array));
+    h->sigmatch_array_size = 1024;
+
+    h->sigs = (struct apply_handle::sigs*)xxmalloc(sizeof(struct apply_handle::sigs)*(maxsigma+1));
+    h->has_flags = 0;
+    h->flag_list = NULL;
+
+    /* Malloc first array of trie and store trie ptrs to be able to free later */
+    /* when apply_clear() is called.                                           */
+
+    h->sigma_trie = (struct apply_handle::sigma_trie*)xxcalloc(256,sizeof(struct apply_handle::sigma_trie));
+    h->sigma_trie_arrays = (struct apply_handle::sigma_trie_arrays*)xxmalloc(sizeof(struct apply_handle::sigma_trie_arrays));
+    h->sigma_trie_arrays->arr = h->sigma_trie;
+    h->sigma_trie_arrays->next = NULL;
+
+    for (i=0;i<256;i++)
+	(h->sigma_trie+i)->next = NULL;
+    for (sig = h->gsigma; sig != NULL && sig->number != -1; sig = sig->next) {
+	if (flag_check(sig->symbol)) {
+	    h->has_flags = 1;
+	    apply_add_flag(h, flag_get_name(sig->symbol));
+	}
+	(h->sigs+(sig->number))->symbol = sig->symbol;
+	(h->sigs+(sig->number))->length = strlen(sig->symbol);
+	/* Add sigma entry to trie */
+	if (sig->number > IDENTITY) {
+	    apply_add_sigma_trie(h, sig->number, sig->symbol, (h->sigs+(sig->number))->length);
+	}
+    }
+    if (maxsigma >= IDENTITY) {
+	(h->sigs+EPSILON)->symbol = h->epsilon_symbol;
+	(h->sigs+EPSILON)->length =  strlen(h->epsilon_symbol);
+	(h->sigs+UNKNOWN)->symbol = "?";
+	(h->sigs+UNKNOWN)->length =  1;
+	(h->sigs+IDENTITY)->symbol = "@";
+	(h->sigs+IDENTITY)->length =  1;
+    }
+    if (h->has_flags) {
+
+        h->flag_lookup = (struct apply_handle::flag_lookup*)xxmalloc(sizeof(struct apply_handle::flag_lookup)*(maxsigma+1));
+	for (i=0; i <= maxsigma; i++) {
+	    (h->flag_lookup+i)->type = 0;
+	    (h->flag_lookup+i)->name = NULL;
+	    (h->flag_lookup+i)->value = NULL;
+	}
+	for (sig = h->gsigma; sig != NULL ; sig = sig->next) {
+	    if (flag_check(sig->symbol)) {
+		(h->flag_lookup+sig->number)->type = flag_get_type(sig->symbol);
+		(h->flag_lookup+sig->number)->name = flag_get_name(sig->symbol);
+		(h->flag_lookup+sig->number)->value = flag_get_value(sig->symbol);
+	    }
+	}
+	apply_mark_flagstates(h);
+    }
+}
+
+/* We need to know which symbols in sigma we can match for all positions           */
+/* in the input string.  Alternatively, if there is no input string as is the case */
+/* when we just list the words or randomly search the graph, we can match          */
+/* any symbol in sigma.                                                            */
+
+/* We create an array that for each position in the input string        */
+/* has information on which symbol we can match at that position        */
+/* as well as how many symbols matching consumes                        */
+
+void apply_create_sigmatch(struct apply_handle *h) {
+    char *symbol;
+    struct apply_handle::sigma_trie *st;
+    int i, j, inlen, lastmatch, consumes, cons;
+    /* We create a sigmatch array only in case we match against a real string */
+    if (((h->mode) & ENUMERATE) == ENUMERATE) {
+	return;
+    }
+    symbol = h->instring;
+    inlen = strlen(symbol);
+    h->current_instring_length = inlen;
+    if (inlen >= h->sigmatch_array_size) {
+	xxfree(h->sigmatch_array);
+	h->sigmatch_array = (struct apply_handle::sigmatch_array*)xxmalloc(sizeof(struct apply_handle::sigmatch_array)*(inlen));
+	h->sigmatch_array_size = inlen;
+    }
+    /* Find longest match in alphabet at current position */
+    /* by traversing the trie of alphabet symbols         */
+    for (i=0; i < inlen; i += consumes ) {
+	st = h->sigma_trie;
+	for (j=0, lastmatch = 0; ; j++) {
+	    if (*(symbol+i+j) == '\0') {
+		break;
+	    }
+	    st = st+(unsigned char)*(symbol+i+j);
+	    if (st->signum != 0) {
+		lastmatch = st->signum;
+		if (st->next == NULL)
+		    break;
+		st = st->next;
+	    } else if (st->next != NULL) {
+		st = st->next;
+	    } else {
+		break;
+	    }
+	}
+	if (lastmatch != 0) {
+	    (h->sigmatch_array+i)->signumber = lastmatch;
+	    consumes = (h->sigs+lastmatch)->length;
+	} else {
+	    /* Not found in trie */
+	    (h->sigmatch_array+i)->signumber = IDENTITY;
+	    consumes = utf8skip(symbol+i)+1;
+	}
+
+	/* If we now find trailing unicode combining characters (0300-036F):      */
+	/* (1) Merge them all with current symbol                                 */
+	/* (2) Declare the whole sequence one ? (IDENTITY) symbol                 */
+        /*     Step 2 is motivated by the fact that                               */
+	/*     if the input is S(symbol) + D(diacritic)                           */
+        /*     and SD were a symbol in the alphabet, then this would have been    */
+        /*     found when searching the alphabet symbols earlier, so SD+ => ?     */
+        /*     Note that this means that a multi-char symbol followed by a        */
+        /*     diacritic gets converted to a single ?, e.g.                       */
+        /*     [TAG] + D => ? if [TAG] is in the alphabet, but [TAG]+D isn't.     */
+
+	for (  ; (cons = utf8iscombining((unsigned char *)(symbol+i+consumes))); consumes += cons) {
+	    (h->sigmatch_array+i)->signumber = IDENTITY;
+	}
+	(h->sigmatch_array+i)->consumes = consumes;
+    }
+}
+
+void apply_add_flag(struct apply_handle *h, char *name) {
+    struct apply_handle::flag_list *flist, *flist_prev;
+    if (h->flag_list == NULL) {
+        flist = h->flag_list = (struct apply_handle::flag_list*)xxmalloc(sizeof(struct apply_handle::flag_list));
+    } else {
+	for (flist = h->flag_list; flist != NULL; flist_prev = flist, flist = flist->next) {
+	    if (strcmp(flist->name, name) == 0) {
+		return;
+	    }
+	}
+	flist = (struct apply_handle::flag_list*)xxmalloc(sizeof(struct apply_handle::flag_list));
+	flist_prev->next = flist;
+    }
+    flist->name = name;
+    flist->value = NULL;
+    flist->neg = 0;
+    flist->next = NULL;
+    return;
+}
+
+void apply_clear_flags(struct apply_handle *h) {
+    struct apply_handle::flag_list *flist;
+    for (flist = h->flag_list; flist != NULL; flist = flist->next) {
+	flist->value = NULL;
+	flist->neg = 0;
+    }
+    return;
+}
+
+/* Check for flag consistency by looking at the current states of */
+/* flags in flist */
+
+int apply_check_flag(struct apply_handle *h, int type, char *name, char *value) {
+    struct apply_handle::flag_list *flist, *flist2;
+    for (flist = h->flag_list; flist != NULL; flist = flist->next) {
+	if (strcmp(flist->name, name) == 0) {
+	    break;
+	}
+    }
+    h->oldflagvalue = flist->value;
+    h->oldflagneg = flist->neg;
+    
+    if (type == FLAG_UNIFY) {
+	if (flist->value == NULL) {
+	    flist->value = xxstrdup(value);
+	    return SUCCEED;
+	}
+	else if (strcmp(value, flist->value) == 0 && flist->neg == 0) {
+	    return SUCCEED;
+	} else if (strcmp(value, flist->value) != 0 && flist->neg == 1) {
+	    flist->value = xxstrdup(value);
+	    flist->neg = 0;
+	    return SUCCEED;
+	}
+	return FAIL;
+    }
+
+    if (type == FLAG_CLEAR) {
+	flist->value = NULL;
+	flist->neg = 0;
+	return SUCCEED;
+    }
+
+    if (type == FLAG_DISALLOW) {
+	if (flist->value == NULL) {
+	    return SUCCEED;
+	}
+	if (value == NULL && flist->value != NULL) {
+	    return FAIL;
+	}
+	if (strcmp(value, flist->value) != 0) {
+            if (flist->neg == 1)
+                return FAIL;
+            return SUCCEED;
+	}
+	if (strcmp(value, flist->value) == 0 && flist->neg == 1) {
+            return SUCCEED;
+        }
+        return FAIL;
+    }
+
+    if (type == FLAG_NEGATIVE) {
+	flist->value = value;
+	flist->neg = 1;
+	return SUCCEED;
+    }
+
+    if (type == FLAG_POSITIVE) {
+	flist->value = value;
+	flist->neg = 0;
+	return SUCCEED;
+    }
+
+    if (type == FLAG_REQUIRE) {
+
+	if (value == NULL) {
+	    if (flist->value == NULL) {
+		return FAIL;
+	    } else {
+		return SUCCEED;
+	    }
+	} else {
+	    if (flist->value == NULL) {
+		return FAIL;
+	    }
+	    if (strcmp(value, flist->value) != 0) {
+		return FAIL;
+	    } else {
+                if (flist->neg == 1) {
+                    return FAIL;
+                }
+		return SUCCEED;
+	    }
+	}
+    }
+
+    if (type == FLAG_EQUAL) {
+	for (flist2 = h->flag_list; flist2 != NULL; flist2 = flist2->next) {
+	    if (strcmp(flist2->name, value) == 0) {
+		break;
+	    }
+	}
+
+	if (flist2 == NULL && flist->value != NULL)
+	    return FAIL;
+	if (flist2 == NULL && flist->value == NULL) {
+	    return SUCCEED;
+	}
+	if (flist2->value == NULL || flist->value == NULL) {
+	    if (flist2->value == NULL && flist->value == NULL && flist->neg == flist2->neg) {
+		return SUCCEED;
+	    } else {
+		return FAIL;
+	    }
+	}  else if (strcmp(flist2->value, flist->value) == 0 && flist->neg == flist2->neg) {
+	    return SUCCEED;
+	}
+	return FAIL;
+    }
+    fprintf(stderr,"***Don't know what do with flag [%i][%s][%s]\n", type, name, value);
+    return FAIL;
+}
diff --git a/back-ends/foma/cpp-version/coaccessible.cc b/back-ends/foma/cpp-version/coaccessible.cc
new file mode 100644
index 0000000..e19d436
--- /dev/null
+++ b/back-ends/foma/cpp-version/coaccessible.cc
@@ -0,0 +1,176 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "foma.h"
+
+struct invtable {
+  int state;
+  struct invtable *next;
+};
+
+struct fsm *fsm_coaccessible(struct fsm *net) {
+
+    struct invtable *inverses, *temp_i, *temp_i_prev, *current_ptr;
+  int i, j, s, t, *coacc, current_state, markcount, *mapping, terminate, new_linecount, new_arccount, *added, old_statecount;
+  
+
+  struct fsm_state *fsm;
+
+  fsm = net->states;
+  new_arccount = 0;
+  /* printf("statecount %i\n",net->statecount); */
+  old_statecount = net->statecount;
+  inverses = (struct invtable *)xxcalloc(net->statecount, sizeof(struct invtable));
+  coacc = (int *)xxmalloc(sizeof(int)*(net->statecount));
+  mapping = (int *)xxmalloc(sizeof(int)*(net->statecount));
+  added = (int *)xxmalloc(sizeof(int)*(net->statecount));
+
+  for (i=0; i < (net->statecount); i++) {
+    (inverses+i)->state = -1;
+    *(coacc+i) = 0;
+    *(added+i) = 0;
+  }
+
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    s = (fsm+i)->state_no;
+    t = (fsm+i)->target;
+    if (t != -1 && s != t) {
+      
+      if (((inverses+t)->state) == -1) {
+	(inverses+t)->state = s;
+      } else {
+        temp_i = (struct invtable *)xxmalloc(sizeof(struct invtable));
+	temp_i->next = (inverses+t)->next;
+	(inverses+t)->next = temp_i;
+	temp_i->state = s;
+      }
+    }
+  }
+
+  /* Push & mark finals */
+
+  markcount = 0;
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    if ((fsm+i)->final_state && (!*(coacc+((fsm+i)->state_no)))) {
+      int_stack_push((fsm+i)->state_no);
+      *(coacc+(fsm+i)->state_no) = 1;
+      markcount++;
+    }
+  }
+
+  terminate = 0;
+  while(!int_stack_isempty()) {
+    current_state = int_stack_pop();
+    current_ptr = inverses+current_state;
+    while(current_ptr != NULL && current_ptr->state != -1) {
+      if (!*(coacc+(current_ptr->state))) {
+	*(coacc+(current_ptr->state)) = 1;
+	int_stack_push(current_ptr->state);
+	markcount++;
+      }
+      current_ptr = current_ptr->next;
+    }
+    if (markcount >= net->statecount) {
+      /* printf("Already coacc\n");  */
+      terminate = 1;
+      int_stack_clear();
+      break;
+    }
+  }
+
+
+  if (terminate == 0) {
+    *mapping = 0; /* state 0 always exists */
+    new_linecount = 0;
+    for (i=1,j=0; i < (net->statecount);i++) {
+      if (*(coacc+i) == 1) {
+	j++;
+	*(mapping+i) = j;
+      }
+    }
+    
+    for (i=0,j=0; (fsm+i)->state_no != -1; i++) {
+      if (i > 0 && (fsm+i)->state_no != (fsm+i-1)->state_no && (fsm+i-1)->final_state && !*(added+((fsm+i-1)->state_no))) {
+	add_fsm_arc(fsm, j++, *(mapping+((fsm+i-1)->state_no)), -1, -1, -1, 1, (fsm+i-1)->start_state);
+	new_linecount++;
+	*(added+((fsm+i-1)->state_no)) = 1;
+	/* printf("addf ad %i\n",i); */
+      }
+      if (*(coacc+((fsm+i)->state_no)) && (((fsm+i)->target == -1) || *(coacc+((fsm+i)->target)))) {
+	(fsm+j)->state_no = *(mapping+((fsm+i)->state_no));
+	if ((fsm+i)->target == -1) {
+	  (fsm+j)->target = -1;
+	} else {
+	  (fsm+j)->target = *(mapping+((fsm+i)->target));
+	}
+	(fsm+j)->final_state = (fsm+i)->final_state;
+	(fsm+j)->start_state = (fsm+i)->start_state;
+	(fsm+j)->in = (fsm+i)->in;
+	(fsm+j)->out = (fsm+i)->out;
+	j++;
+	new_linecount++;
+	*(added+(fsm+i)->state_no) = 1;
+	if ((fsm+i)->target != -1) {
+	  new_arccount++;
+	}
+      }
+    }
+
+    if ((i > 1) && ((fsm+i-1)->final_state) && *(added+((fsm+i-1)->state_no)) == 0) {
+      /* printf("addf\n"); */
+      add_fsm_arc(fsm, j++, *(mapping+((fsm+i-1)->state_no)), -1, -1, -1, 1, (fsm+i-1)->start_state);
+      new_linecount++;
+    }
+
+    if (new_linecount == 0) {
+      add_fsm_arc(fsm, j++, 0, -1, -1, -1, -1, -1);
+    }
+  
+    add_fsm_arc(fsm, j, -1, -1, -1, -1, -1, -1);
+    if (markcount == 0) {
+      /* We're dealing with the empty language */
+      xxfree(fsm);
+      net->states = fsm_empty();
+      fsm_sigma_destroy(net->sigma);
+      net->sigma = sigma_create();
+    }
+    net->linecount = new_linecount;
+    net->arccount = new_arccount;
+    net->statecount = markcount;
+  }
+
+  /* printf("Markccount %i \n",markcount); */
+  
+  for (i = 0; i < old_statecount ; i++) {
+      for (temp_i = inverses+i; temp_i != NULL ; ) {
+          temp_i_prev = temp_i;
+          temp_i = temp_i->next;
+          if (temp_i_prev != inverses+i)
+              xxfree(temp_i_prev);
+      }
+  }
+  xxfree(inverses);
+
+  xxfree(coacc);
+  xxfree(added);
+  xxfree(mapping);
+  net->is_pruned = YES;
+  return(net);
+}
diff --git a/back-ends/foma/cpp-version/constructions.cc b/back-ends/foma/cpp-version/constructions.cc
new file mode 100644
index 0000000..b114009
--- /dev/null
+++ b/back-ends/foma/cpp-version/constructions.cc
@@ -0,0 +1,3168 @@
+/*   Foma: a finite-state toolkit and library.                                 */
+/*   Copyright © 2008-2015 Mans Hulden                                         */
+
+/*   This file is part of foma.                                                */
+
+/*   Licensed under the Apache License, Version 2.0 (the "License");           */
+/*   you may not use this file except in compliance with the License.          */
+/*   You may obtain a copy of the License at                                   */
+
+/*      http://www.apache.org/licenses/LICENSE-2.0                             */
+
+/*   Unless required by applicable law or agreed to in writing, software       */
+/*   distributed under the License is distributed on an "AS IS" BASIS,         */
+/*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
+/*   See the License for the specific language governing permissions and       */
+/*   limitations under the License.                                            */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "foma.h"
+
+#define KLEENE_STAR 0
+#define KLEENE_PLUS 1
+#define OPTIONALITY 2
+
+#define COMPLEMENT 0
+#define COMPLETE 1
+
+#define STACK_3_PUSH(a,b,c) int_stack_push(a); int_stack_push(b); int_stack_push(c);
+#define STACK_2_PUSH(a,b) int_stack_push(a); int_stack_push(b);
+
+struct mergesigma {
+  char *symbol;
+  unsigned char presence; /* 1 = in net 1, 2 = in net 2, 3 = in both */
+  int number;
+  struct mergesigma *next;
+};
+
+int sort_cmp(const void *a, const void *b) {
+  return (((const struct fsm_state *)a)->state_no - ((const struct fsm_state *)b)->state_no);
+}
+
+INLINE int add_fsm_arc(struct fsm_state *fsm, int offset, int state_no, int in, int out, int target, int final_state, int start_state);
+
+struct fsm *fsm_kleene_closure(struct fsm *net, int optionality);
+
+struct fsm *fsm_kleene_star(struct fsm *net) {
+  return (fsm_kleene_closure(net, KLEENE_STAR));
+}
+
+struct fsm *fsm_kleene_plus(struct fsm *net) {
+  return (fsm_kleene_closure(net, KLEENE_PLUS));
+}
+
+struct fsm *fsm_optionality(struct fsm *net) {
+  return (fsm_kleene_closure(net, OPTIONALITY));
+}
+
+struct fsm *fsm_escape(char *symbol) {
+  return(fsm_symbol(symbol+1));
+}
+
+/* Convert a multicharacter-string-containing machine */
+/* to the equivalent "letter" machine where all arcs  */
+/* are single utf8 letters.                           */
+
+struct fsm *fsm_letter_machine(struct fsm *net) {
+   
+    struct fsm *outnet;
+    struct fsm_read_handle *inh;
+    struct fsm_construct_handle *outh;
+    int i, steps, source, target, addstate, innum, outnum, inlen, outlen;
+    char *in, *out, *currin, *currout, tmpin[128], tmpout[128];
+
+    inh = fsm_read_init(fsm_minimize(net));
+    outh = fsm_construct_init("name");
+    addstate = net->statecount;
+
+    while (fsm_get_next_arc(inh)) {
+        in = fsm_get_arc_in(inh);
+	out = fsm_get_arc_out(inh);
+	innum = fsm_get_arc_num_in(inh);
+	outnum = fsm_get_arc_num_out(inh);
+	source = fsm_get_arc_source(inh);
+	target = fsm_get_arc_target(inh);
+	
+	if (((innum > IDENTITY) && utf8strlen(in) > 1) || ((outnum > IDENTITY) && utf8strlen(out) > 1)) {
+	    inlen = innum <= IDENTITY ? 1 : utf8strlen(in);
+	    outlen = outnum <= IDENTITY ? 1 : utf8strlen(out);
+	    steps = inlen > outlen ? inlen : outlen;
+
+	    target = addstate;
+	    for (i = 0; i < steps; i++) {
+		if (innum <= IDENTITY || inlen < 1) {
+		    if (inlen < 1)
+			currin = "@_EPSILON_SYMBOL_@";
+		    else
+			currin = in;
+		} else {
+		    strncpy(tmpin, in, utf8skip(in)+1);
+		    *(tmpin+utf8skip(in)+1) = '\0';
+		    currin = tmpin;
+		    inlen--;
+		    in = in+utf8skip(in)+1;
+		}
+		if (outnum <= IDENTITY || outlen < 1) {
+		    if (outlen < 1)
+			currout = "@_EPSILON_SYMBOL_@";
+		    else
+			currout = out;
+		} else {
+		    strncpy(tmpout, out, utf8skip(in)+1);
+		    *(tmpout+utf8skip(out)+1) = '\0';
+		    currout = tmpout;
+		    out = out+utf8skip(out)+1;
+		    outlen--;
+		}
+		if (i == 0 && steps > 1) {
+		    target = addstate;
+		    addstate++;
+		}
+		if (i > 0 && (steps-i == 1)) {
+		    source = addstate - 1;
+		    target = fsm_get_arc_target(inh);
+		}
+		if (i > 0 && (steps-i != 1)) {
+		    source = addstate-1;
+		    target = addstate;
+		    addstate++;
+		}
+		fsm_construct_add_arc(outh,source,target,currin,currout);
+	    }
+	} else {
+	    fsm_construct_add_arc(outh,source,target,in,out);
+	}
+    }
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(outh, i);
+    }
+    while ((i = fsm_get_next_initial(inh)) != -1) {
+	fsm_construct_set_initial(outh, i);
+    }
+    fsm_read_done(inh);
+    outnet = fsm_construct_done(outh);
+    return(outnet);
+}
+
+struct fsm *fsm_explode(char *symbol) {
+    struct fsm *net;
+    struct fsm_construct_handle *h;
+    char *tempstring;
+    int length, i, j, skip;
+
+    h = fsm_construct_init("");
+    fsm_construct_set_initial(h,0);
+    
+    length = strlen(symbol)-2;
+    for (i=1, j=1; i <= length; i += skip, j++) {
+	skip = utf8skip(symbol+i)+1;
+	tempstring = xxstrndup(((symbol+i)),skip);
+	fsm_construct_add_arc(h,j-1,j,tempstring,tempstring);
+	xxfree(tempstring);
+    }
+    fsm_construct_set_final(h, j-1);
+    net = fsm_construct_done(h);
+    return(net);
+}
+
+struct fsm *fsm_symbol(char *symbol) {
+  struct fsm *net;
+  int symbol_no;
+
+  net = fsm_create("");
+  fsm_update_flags(net, YES, YES, YES, YES, YES, NO);
+  if (strcmp(symbol,"@_EPSILON_SYMBOL_@")==0) {
+    /* Epsilon */
+    (void)sigma_add_special(EPSILON, net->sigma);
+    net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*2);
+    add_fsm_arc(net->states, 0, 0, -1,-1,-1,1,1);
+    add_fsm_arc(net->states, 1, -1,-1,-1,-1,-1,-1);
+    net->arccount = 0;
+    net->statecount = 1;
+    net->linecount = 1;
+    net->finalcount = 1;
+    net->is_deterministic = NO;
+    net->is_minimized = NO;
+    net->is_epsilon_free = NO;
+  } else {
+    if ((strcmp(symbol,"@_IDENTITY_SYMBOL_@") == 0)) {
+      symbol_no = sigma_add_special(IDENTITY,net->sigma);
+    } else {
+      symbol_no = sigma_add(symbol,net->sigma);
+    }
+    net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*3);
+    add_fsm_arc(net->states, 0, 0, symbol_no, symbol_no, 1, 0, 1);
+    add_fsm_arc(net->states, 1, 1, -1, -1, -1, 1, 0);
+    add_fsm_arc(net->states, 2, -1, -1, -1, -1, -1, -1);
+    net->arity = 1;
+    net->pathcount = 1;
+    net->arccount = 1;
+    net->statecount = 2;
+    net->linecount = 2;
+    net->finalcount = 1;
+    net->arcs_sorted_in = YES;
+    net->arcs_sorted_out = YES;
+    net->is_deterministic = YES;
+    net->is_minimized = YES;
+    net->is_epsilon_free = YES;
+  }
+  return(net);
+}
+
+void fsm_sort_lines(struct fsm *net) {
+  struct fsm_state *fsm;
+  fsm = net->states;
+  qsort(fsm, find_arccount(fsm), sizeof(struct fsm_state), sort_cmp);
+}
+
+void fsm_update_flags(struct fsm *net, int det, int pru, int min, int eps, int loop, int completed) {
+  net->is_deterministic = det;
+  net->is_pruned = pru;
+  net->is_minimized = min;
+  net->is_epsilon_free = eps;
+  net->is_loop_free = loop;
+  net->is_completed = completed;
+  net->arcs_sorted_in = NO;
+  net->arcs_sorted_out = NO;
+}
+
+int fsm_count_states(struct fsm_state *fsm) {
+  int i, temp = -1, states = 0;
+  for(i=0; (fsm+i)->state_no != -1; i++) {
+    if (temp != (fsm+i)->state_no) {
+      states++;
+      temp = (fsm+i)->state_no;
+    }
+  }
+  return(states);
+}
+
+struct state_arr {
+  int final;
+  int start;
+  struct fsm_state *transitions;
+};
+
+struct state_arr *init_state_pointers(struct fsm_state *fsm_state) {
+
+  /* Create an array for quick lookup of whether states are final, and a pointer to the first line regarding each state */
+
+  struct state_arr *state_arr;
+  int states, i, sold;
+  sold = -1;
+  states = fsm_count_states(fsm_state);
+  state_arr = (struct state_arr *)xxmalloc(sizeof(struct state_arr)*(states+1));
+  for (i=0; i<states; i++) {
+    (state_arr+i)->final = 0;
+    (state_arr+i)->start = 0;
+  }
+  
+  for (i=0; (fsm_state+i)->state_no != -1; i++) {
+    if ((fsm_state+i)->final_state == 1)
+      (state_arr+((fsm_state+i)->state_no))->final = 1;
+    if ((fsm_state+i)->start_state == 1)
+      (state_arr+((fsm_state+i)->state_no))->start = 1;
+    if ((fsm_state+i)->state_no != sold) {
+      (state_arr+((fsm_state+i)->state_no))->transitions = (fsm_state+i);
+      sold = (fsm_state+i)->state_no;
+    }
+  }
+  return(state_arr);
+}
+
+/* An open addressing scheme (with linear probing) to store triplets of ints */
+/* and hashing them with an automatically increasing key at every insert     */
+/* The table is rehashed whenever occupancy reaches 0.5                      */
+
+struct triplethash_triplets {
+    int a;
+    int b;
+    int c;
+    int key;
+};
+
+struct triplethash {
+    struct triplethash_triplets *triplets;
+    unsigned int tablesize;
+    int occupancy;
+};
+
+struct triplethash *triplet_hash_init() {
+    struct triplethash *th;
+    int i;
+    th = (struct triplethash *)xxmalloc(sizeof(struct triplethash));
+    th->tablesize = 128;
+    th->occupancy = 0;
+    th->triplets = (struct triplethash_triplets *)xxmalloc(sizeof(struct triplethash_triplets) * th->tablesize);
+    for (i = 0; i < th->tablesize; i++) {
+	(th->triplets+i)->key = -1;
+    }
+    return(th);
+}
+
+unsigned int triplethash_hashf(int a, int b, int c) {
+    return((unsigned int)(a * 7907 + b * 86028157 + c * 7919));
+}
+
+void triplet_hash_free(struct triplethash *th) {
+    if (th != NULL) {
+	if (th->triplets != NULL) {
+	    xxfree(th->triplets);
+	}
+	xxfree(th);
+    }
+}
+
+void triplet_hash_rehash(struct triplethash *th);
+
+void triplet_hash_insert_with_key(struct triplethash *th, int a, int b, int c, int key) {
+    struct triplethash_triplets *th_table;
+    unsigned int hash;
+    th_table = th->triplets;
+    hash = triplethash_hashf(a, b, c) % th->tablesize;
+    for (;;) {
+	if ((th_table + hash)->key == -1) {
+	    (th_table + hash)->key = key;
+	    (th_table + hash)->a = a;
+	    (th_table + hash)->b = b;
+	    (th_table + hash)->c = c;
+	    break;
+	}
+	hash++;
+	if (hash >= th->tablesize)
+	    hash -= th->tablesize;
+    }
+}
+
+int triplet_hash_insert(struct triplethash *th, int a, int b, int c) {
+    struct triplethash_triplets *th_table;
+    unsigned int hash;
+    th_table = th->triplets;
+    hash = triplethash_hashf(a,b,c) % th->tablesize;
+    for (;;) {
+	if ((th_table + hash)->key == - 1) {
+	    (th_table + hash)->key = th->occupancy;
+	    (th_table + hash)->a = a;
+	    (th_table + hash)->b = b;
+	    (th_table + hash)->c = c;
+	    th->occupancy = th->occupancy + 1;
+	    if (th->occupancy > th->tablesize / 2) {
+		triplet_hash_rehash(th);
+	    }
+	    return(th->occupancy - 1);
+	}
+	hash++;
+	if (hash >= th->tablesize)
+	    hash -= th->tablesize;
+    }
+}
+
+void triplet_hash_rehash(struct triplethash *th) {
+    int i;
+    unsigned int newtablesize, oldtablesize;
+    struct triplethash_triplets *oldtriplets;
+    newtablesize = th->tablesize * 2;
+    oldtablesize = th->tablesize;
+    oldtriplets = th->triplets;
+    th->triplets = (struct triplethash_triplets *)xxmalloc(sizeof(struct triplethash_triplets) * newtablesize);
+    th->tablesize = newtablesize;
+    for (i = 0; i < newtablesize; i++) {
+	(th->triplets+i)->key = -1;
+    }
+    for (i = 0; i < oldtablesize; i++) {
+	if ((oldtriplets+i)-> key != -1) {
+	    triplet_hash_insert_with_key(th, (oldtriplets+i)->a, (oldtriplets+i)->b, (oldtriplets+i)->c, (oldtriplets+i)->key);
+	}
+    }
+    xxfree(oldtriplets);
+}
+
+int triplet_hash_find(struct triplethash *th, int a, int b, int c) {
+    struct triplethash_triplets *th_table;
+    unsigned int hash, j;
+    th_table = th->triplets;
+    hash = triplethash_hashf(a, b, c) % th->tablesize;
+    for (j = 0; j < th->tablesize; j++) {
+	if ((th_table + hash)->key == - 1)
+	    return -1;
+	if ((th_table + hash)->a == a && (th_table + hash)->b == b && (th_table + hash)->c == c) {
+	    return((th_table + hash)->key);
+	}
+	hash++;
+	if (hash >= th->tablesize)
+	    hash -= th->tablesize;
+    }
+    return -1;
+}
+
+struct fsm *fsm_intersect(struct fsm *net1, struct fsm *net2) {
+
+    struct blookup {int mainloop; int target; } *array, *bptr;
+    int a,b,current_state, current_start, current_final, target_number, sigma2size, mainloop;
+    struct fsm_state *machine_a, *machine_b;
+    struct state_arr *point_a, *point_b;
+    struct fsm *new_net;
+    struct triplethash *th;
+
+    net1 = fsm_minimize(net1);
+    net2 = fsm_minimize(net2);
+
+    if (fsm_isempty(net1) || fsm_isempty(net2)) {
+	fsm_destroy(net1);
+	fsm_destroy(net2);
+	return(fsm_empty_set());
+    }
+
+    fsm_merge_sigma(net1, net2);
+    
+    fsm_update_flags(net1, YES, NO, UNK, YES, UNK, UNK);
+    
+    machine_a = net1->states;
+    machine_b = net2->states;
+
+    sigma2size = sigma_max(net2->sigma)+1;
+    array = (struct blookup *)xxcalloc(sigma2size*sigma2size, sizeof(struct blookup));
+    mainloop = 0;
+
+    /* Intersect two networks by the running-in-parallel method */
+    /* new state 0 = {0,0} */
+    
+    STACK_2_PUSH(0,0);
+    
+    th = triplet_hash_init();
+    triplet_hash_insert(th, 0, 0, 0);
+
+    fsm_state_init(sigma_max(net1->sigma));
+    
+    point_a = init_state_pointers(machine_a);
+    point_b = init_state_pointers(machine_b);
+    
+    while (!int_stack_isempty()) {
+        
+        /* Get a pair of states to examine */
+        
+        a = int_stack_pop();
+        b = int_stack_pop();
+        
+	current_state = triplet_hash_find(th, a, b, 0);
+        current_start = (((point_a+a)->start == 1) && ((point_b+b)->start == 1)) ? 1 : 0;
+        current_final = (((point_a+a)->final == 1) && ((point_b+b)->final == 1)) ? 1 : 0;
+        
+        fsm_state_set_current_state(current_state, current_final, current_start);
+
+        /* Create a lookup index for machine b */
+        /* array[in][out] holds the target for this state and the symbol pair in:out */
+        /* Also, we keep track of whether an entry is fresh by the mainloop counter */
+        /* so we don't mistakenly use an old entry and don't have to clear the table */
+        /* between each state pair we encounter */
+
+        for (mainloop++, machine_b = (point_b+b)->transitions; machine_b->state_no == b; machine_b++) {
+            if (machine_b->in < 0) continue;
+            bptr = array+(machine_b->in*sigma2size)+machine_b->out;
+            bptr->mainloop = mainloop;
+            bptr->target = machine_b->target;
+        }
+
+        /* The main loop where we run the machines in parallel */
+        /* We look at each transition of a in this state, and consult the index of b */
+        /* we just created */
+
+        for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a ; machine_a++) {
+            if (machine_a->in < 0 || machine_a->out < 0) continue;
+            bptr = array+(machine_a->in*sigma2size)+machine_a->out;
+
+            if (bptr->mainloop != mainloop)
+                continue;
+                
+            if ((target_number = triplet_hash_find(th, machine_a->target, bptr->target, 0)) == -1) {
+                STACK_2_PUSH(bptr->target, machine_a->target);
+                target_number = triplet_hash_insert(th, machine_a->target, bptr->target, 0);
+            }
+            
+            fsm_state_add_arc(current_state, machine_a->in, machine_a->out, target_number, current_final, current_start);
+            
+        }
+        fsm_state_end_state();
+    }
+    new_net = fsm_create("");
+    fsm_sigma_destroy(new_net->sigma);
+    new_net->sigma = net1->sigma;
+    net1->sigma = NULL;
+    fsm_destroy(net2);
+    fsm_destroy(net1);
+    fsm_state_close(new_net);
+    xxfree(point_a);
+    xxfree(point_b);
+    xxfree(array);
+    triplet_hash_free(th);
+    return(fsm_coaccessible(new_net));
+}
+
+struct fsm *fsm_compose(struct fsm *net1, struct fsm *net2) {
+
+    
+    /* The composition algorithm is the basic naive composition where we lazily      */
+    /* take the cross-product of states P and Q and move to a new state with symbols */
+    /* ain, bout if the symbols aout = bin.  Also, if aout = 0 state p goes to       */
+    /* its target, while q stays.  Similarly, if bin = 0, q goes to its target       */
+    /* while p stays.                                                                */
+
+    /* We have two variants of the algorithm to avoid creating multiple paths:       */
+    /* 1) Bistate composition.  In this variant, when we create a new state, we call it */
+    /*    (p,q,mode) where mode = 0 or 1, depending on what kind of an arc we followed  */
+    /*    to get there.  If we followed an x:y arc where x and y are both real symbols  */
+    /*    we always go to mode 0, however, if we followed an 0:y arc, we go to mode 1.  */
+    /*    from mode 1, we do not follow x:0 arcs.  Each (p,q,mode) is unique, and       */
+    /*    from (p,q,X) we always consider the transitions from p and q.                 */
+    /*    We never create arcs (x:0 0:y) yielding x:y.                                  */
+
+    /* 2) Tristate composition. Here we always go to mode 0 with a x:y arc.             */
+    /*    (x:0,0:y) yielding x:y is allowed, but only in mode 0                         */
+    /*    (x:y y:z) is always allowed and results in target = mode 0                    */
+    /*    0:y arcs lead to mode 2, and from there we stay in mode 2 with 0:y            */
+    /*    in mode 2 we only consider 0:y and x:y arcs                                   */
+    /*    x:0 arcs lead to mode 1, and from there we stay in mode 1 with x:0            */
+    /*    in mode 1 we only consider x:0 and x:y arcs                                   */
+
+    /* It seems unsettled which type of composition is better.  Tristate is similar to  */
+    /* the filter transducer given in Mohri, Pereira and Riley (1996) and works well    */
+    /* for cases such as [a:0 b:0 c:0 .o. 0:d 0:e 0:f], yielding the shortest path.     */
+    /* However, for generic cases, bistate seems to yield smaller transducers.          */
+    /* The global variable g_compose_tristate is set to OFF by default                  */
+
+    struct outarray {
+        short int symin;
+        short int symout;
+        int target;
+        int mainloop;
+    } *outarray, *iptr, *currtail;
+
+    struct index {
+        struct outarray *tail;
+    } *index;
+
+    extern int g_compose_tristate, g_flag_is_epsilon;
+    int a,b,i,mainloop,current_state, current_start, current_final, target_number, ain, bin, aout, bout, asearch, max2sigma;
+    struct fsm_state *machine_a, *machine_b;
+    struct state_arr *point_a, *point_b;
+    struct triplethash *th;
+    int mode;
+    Boolean *is_flag = NULL;
+
+
+    net1 = fsm_minimize(net1);
+    net2 = fsm_minimize(net2);
+
+    if (fsm_isempty(net1) || fsm_isempty(net2)) {
+	fsm_destroy(net1);
+	fsm_destroy(net2);
+	return(fsm_empty_set());
+    }
+    
+    /* If flag-is-epsilon is on, we need to add the flag symbols    */
+    /* in both networks to each other's sigma so that UNKNOWN       */
+    /* or IDENTITY symbols do not match these flags, since they are */
+    /* supposed to have the behavior of EPSILON                     */
+    /* And we need to do this before merging the sigmas, of course  */
+
+    if (g_flag_is_epsilon) {
+        struct sigma *sig1, *sig2;
+        int flags1, flags2;
+        flags1 = flags2 = 0;
+        sig2 = net2->sigma;
+        max2sigma = sigma_max(net2->sigma);
+        for (sig1 = net1->sigma; sig1 != NULL; sig1 = sig1->next) {
+            if (flag_check(sig1->symbol)) {
+                flags1 = 1;
+                if (sigma_find(sig1->symbol, sig2) == -1) {
+                    sigma_add(sig1->symbol, sig2);
+                }
+            }
+        }
+
+        sig1 = net1->sigma;
+        for (sig2 = net2->sigma; sig2 != NULL ; sig2 = sig2->next) {
+            if (flag_check(sig2->symbol)) {
+                if (sig2->number <= max2sigma) {
+                    flags2 = 1;
+                }
+                if (sigma_find(sig2->symbol, sig1) == -1) {
+                    sigma_add(sig2->symbol, sig1);
+                }
+            }
+        }
+        sigma_sort(net2);
+        sigma_sort(net1);
+        if (flags1 && flags2) {
+            printf("***Warning: flag-is-epsilon is ON and both networks contain flags in composition.  This may yield incorrect results.  Set flag-is-epsilon to OFF.\n");
+        }
+    }
+
+    fsm_merge_sigma(net1, net2);
+
+    if (g_flag_is_epsilon) {
+        /* Create lookup table for quickly checking if a symbol is a flag */
+        struct sigma *sig1;
+        is_flag = (bool *)xxmalloc(sizeof(Boolean)*(sigma_max(net1->sigma)+1));
+        for (sig1 = net1->sigma; sig1 != NULL; sig1=sig1->next) {
+            if (flag_check(sig1->symbol)) {
+                *(is_flag+(sig1->number)) = 1;
+            } else {
+                *(is_flag+(sig1->number)) = 0;
+            }
+        }
+    }
+
+    fsm_update_flags(net1, YES, NO, UNK, YES, UNK, UNK);
+    
+    machine_a = net1->states;
+    machine_b = net2->states;
+
+    max2sigma = sigma_max(net2->sigma);
+
+    /* Create an index for looking up input symbols in machine b quickly */
+    /* We store each machine_b->in symbol in outarray[symin][...] */
+    /* the array index[symin] points to the tail of the current list in outarray */
+    /* (we may have many entries for one input symbol as there may be many outputs */
+    /* The field mainloop tells us whether the entry is current as we want to loop */
+    /* UNKNOWN and IDENTITY are indexed as UNKNOWN because we need to find both */
+    /* as they share some semantics */
+
+    index = (struct index *)xxcalloc(max2sigma+1, sizeof(struct index));
+    outarray = (struct outarray *)xxcalloc((max2sigma+2)*(max2sigma+1), sizeof(struct outarray));
+
+    for (i=0; i <= max2sigma; i++) {
+        (index+i)->tail = outarray + ((max2sigma+2)*i);
+    }
+
+
+    /* Mode, a, b */
+    STACK_3_PUSH(0,0,0);
+
+    th = triplet_hash_init();
+    triplet_hash_insert(th, 0, 0, 0);
+
+    fsm_state_init(sigma_max(net1->sigma));
+    
+    point_a = init_state_pointers(machine_a);
+    point_b = init_state_pointers(machine_b);
+    
+    mainloop = 0;
+
+    while (!int_stack_isempty()) {
+        
+        /* Get a pair of states to examine */
+        
+        a = int_stack_pop();
+        b = int_stack_pop();
+        mode = int_stack_pop();
+        
+	current_state = triplet_hash_find(th, a,b,mode);
+        current_start = (((point_a+a)->start == 1) && ((point_b+b)->start == 1) && (mode == 0)) ? 1 : 0;
+        current_final = (((point_a+a)->final == 1) && ((point_b+b)->final == 1)) ? 1 : 0;
+        
+        fsm_state_set_current_state(current_state, current_final, current_start);
+
+        /* Create the index for machine b in this state */
+        for (mainloop++, machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+            int bindex;
+            /* Index b */
+            bindex = (machine_b->in == IDENTITY) ? UNKNOWN : machine_b->in;
+            if (bindex < 0 || machine_b->target < 0)
+                continue;
+
+            iptr = (index+bindex)->tail;
+            if (iptr->mainloop != mainloop) {
+                iptr = (index+bindex)->tail = outarray+(bindex*(max2sigma+2));
+            } else {
+                iptr++;
+            }
+            iptr->symin = machine_b->in;
+            iptr->symout = machine_b->out;
+            iptr->mainloop = mainloop;
+            iptr->target = machine_b->target;
+            (index+bindex)->tail = iptr;
+        }
+
+        for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a ; machine_a++) {
+
+            /* If we have the same transition from (a,b)-> some state */
+            /* If we have x:y y:z trans to some state */
+            aout = machine_a->out;
+            ain = machine_a->in;
+            /* IDENTITY is indexed under UNKNOWN (see above) */
+            asearch = (aout == IDENTITY) ? UNKNOWN : aout;
+            if (aout < 0) continue;
+            iptr = outarray+(asearch*(max2sigma+2));
+            currtail = (index+asearch)->tail + 1;
+            for ( ; iptr != currtail && iptr->mainloop == mainloop ; iptr++) {
+                
+                ain = machine_a->in;
+                aout = machine_a->out;
+                bin = iptr->symin;
+                bout = iptr->symout;
+                
+                if (aout == IDENTITY && bin == UNKNOWN) {
+                    ain = aout = UNKNOWN;
+                }
+                else if (aout == UNKNOWN && bin == IDENTITY) {
+                    bin = bout = UNKNOWN;
+                }
+                
+                if (!g_compose_tristate) {
+                    if (bin == aout && bin != -1 && bin != EPSILON) {
+                        /* mode -> 0 */
+                        if ((target_number = triplet_hash_find(th, machine_a->target, iptr->target, 0)) == -1) {
+                            STACK_3_PUSH(0, iptr->target, machine_a->target);
+                            target_number = triplet_hash_insert(th, machine_a->target, iptr->target, 0);
+                        }
+                        
+                        fsm_state_add_arc(current_state, ain, bout, target_number, current_final, current_start);
+                    }
+                }
+
+                else if (g_compose_tristate) {
+                    if (bin == aout && bin != -1 && ((bin != EPSILON || mode == 0))) {
+                        /* mode -> 0 */
+                        if ((target_number = triplet_hash_find(th, machine_a->target, iptr->target, 0)) == -1) {
+                            STACK_3_PUSH(0, iptr->target, machine_a->target);
+                            target_number = triplet_hash_insert(th, machine_a->target, iptr->target, 0);
+                        }
+                        
+                        fsm_state_add_arc(current_state, ain, bout, target_number, current_final, current_start);
+                    }
+                }
+                                
+            }
+        }
+        
+        /* Treat epsilon outputs on machine a (may include flags) */
+        for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a ; machine_a++) {
+            aout = machine_a->out;
+            if (aout != EPSILON && g_flag_is_epsilon == 0)
+                continue;
+            ain = machine_a->in;
+
+            if (g_flag_is_epsilon && aout != -1 && mode == 0 && *(is_flag+aout)) {
+                if ((target_number = triplet_hash_find(th, machine_a->target, b, 0)) == -1) {
+                    STACK_3_PUSH(0, b, machine_a->target);
+		    target_number = triplet_hash_insert(th, machine_a->target, b, 0);
+                }
+                fsm_state_add_arc(current_state, ain, aout, target_number, current_final, current_start);
+            }
+
+            if (!g_compose_tristate) {
+                /* Check A:0 arcs on upper side */
+                if (aout == EPSILON && mode == 0) {
+                    /* mode -> 0 */
+                    if ((target_number = triplet_hash_find(th, machine_a->target, b, 0)) == -1) {
+                        STACK_3_PUSH(0, b, machine_a->target);
+                        target_number = triplet_hash_insert(th, machine_a->target, b, 0);
+                    }
+                    
+                    fsm_state_add_arc(current_state, ain, EPSILON, target_number, current_final, current_start);
+                }
+            }
+
+            else if (g_compose_tristate) {
+                if (aout == EPSILON && (mode != 2)) {
+                    /* mode -> 1 */
+                    if ((target_number = triplet_hash_find(th, machine_a->target, b, 1)) == -1) {
+                        STACK_3_PUSH(1, b, machine_a->target);
+                        target_number = triplet_hash_insert(th, machine_a->target, b, 1);
+                    }
+                    
+                    fsm_state_add_arc(current_state, ain, EPSILON, target_number, current_final, current_start);
+                    
+                }
+            }
+            
+        }
+        /* Treat epsilon inputs on machine b (may include flags) */
+        for (machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+            bin = machine_b->in;
+            if (bin != EPSILON && g_flag_is_epsilon == 0)
+                continue;
+
+            bout = machine_b->out;
+            
+            if (g_flag_is_epsilon && bin != -1 && *(is_flag+bin)) {
+                if ((target_number = triplet_hash_find(th, a, machine_b->target, 1)) == -1) {
+                    STACK_3_PUSH(1, machine_b->target,a);
+                    target_number = triplet_hash_insert(th, a, machine_b->target, 1);
+                }
+                fsm_state_add_arc(current_state, bin, bout, target_number, current_final, current_start);
+            }
+
+            if (!g_compose_tristate) {
+                /* Check 0:A arcs on lower side */
+                if (bin == EPSILON) {
+                    /* mode -> 1 */
+                    if ((target_number = triplet_hash_find(th, a, machine_b->target, 1)) == -1) {
+                        STACK_3_PUSH(1, machine_b->target,a);
+                        target_number = triplet_hash_insert(th, a, machine_b->target, 1);
+                    }
+                    
+                    fsm_state_add_arc(current_state, EPSILON, bout, target_number, current_final, current_start);
+                }
+            }
+
+            else if (g_compose_tristate) {
+                /* Check 0:A arcs on lower side */
+                if (bin == EPSILON && mode != 1) {
+                    /* mode -> 1 */
+                    if ((target_number = triplet_hash_find(th, a, machine_b->target, 2)) == -1) {
+                        STACK_3_PUSH(2, machine_b->target, a);
+                        target_number = triplet_hash_insert(th, a, machine_b->target, 2);
+                    }
+                    
+                    fsm_state_add_arc(current_state, EPSILON, bout, target_number, current_final, current_start);
+                }
+            }
+        }
+        fsm_state_end_state();
+    }
+    
+    xxfree(net1->states);
+    fsm_destroy(net2);
+    fsm_state_close(net1);
+    xxfree(point_a);
+    xxfree(point_b);
+    xxfree(index);
+    xxfree(outarray);
+
+    if (g_flag_is_epsilon)
+        xxfree(is_flag);
+    triplet_hash_free(th);
+    net1 = fsm_topsort(fsm_coaccessible(net1));
+    return(fsm_coaccessible(net1));
+}
+
+struct mergesigma *add_to_mergesigma(struct mergesigma *msigma, struct sigma *sigma, short int presence) {
+  int number = 0;
+
+  if (msigma->number == -1) {
+    number = 2;
+  } else {
+    msigma->next = (struct mergesigma *)xxmalloc(sizeof(struct mergesigma));
+    number = msigma->number;
+    msigma = msigma->next;
+    msigma->next = NULL;
+  }
+
+  if (sigma->number < 3) {
+    msigma->number = sigma->number;
+  } else {
+    if (number < 3)
+      number = 2;
+    msigma->number = number+1;
+  }
+  msigma->symbol = sigma->symbol;
+  msigma->presence = presence;
+  return(msigma);
+}
+
+struct sigma *copy_mergesigma(struct mergesigma *mergesigma) {
+    struct sigma *sigma, *new_sigma;
+    
+    sigma = new_sigma = NULL;
+    while(mergesigma != NULL) {
+	if (sigma == NULL) {
+	    sigma = (struct sigma *)xxmalloc(sizeof(struct sigma));
+	    new_sigma = sigma;
+	} else {
+	    sigma->next = (struct sigma *)xxmalloc(sizeof(struct sigma));
+	    sigma = sigma->next;
+	}
+	sigma->next = NULL;
+	sigma->number = mergesigma->number;
+	
+	sigma->symbol = NULL;
+	if (mergesigma->symbol != NULL)
+	    sigma->symbol = xxstrdup(mergesigma->symbol);
+	mergesigma = mergesigma->next;
+    }
+    return(new_sigma);
+}
+
+void fsm_merge_sigma(struct fsm *net1, struct fsm *net2) {
+
+  struct sigma *sigma_1, *sigma_2, *new_sigma_1 = NULL, *new_sigma_2 = NULL;
+  struct mergesigma *mergesigma, *mergesigma2, *start_mergesigma;
+  struct fsm_state *fsm_state, *new_1_state, *new_2_state;
+  int i, j, end_1 = 0, end_2 = 0, sigmasizes, *mapping_1, *mapping_2, equal = 1, unknown_1 = 0, unknown_2 = 0, net_unk = 0, net_adds = 0, net_lines;
+
+#ifdef ORIGINAL
+  i = sigma_find(".#.", net1->sigma);
+  j = sigma_find(".#.", net2->sigma);
+  if (i != -1 && j == -1) {
+      sigma_add(".#.", net2->sigma);
+      sigma_sort(net2);
+  }
+  if (j != -1 && i == -1) {
+      sigma_add(".#.", net1->sigma);
+      sigma_sort(net1);
+  }
+#else
+  // This is handled by HFST's XfstCompiler, if needed.
+#endif
+
+  sigma_1 = net1->sigma;
+  sigma_2 = net2->sigma;
+
+  sigmasizes = sigma_size(sigma_1) + sigma_size(sigma_2);
+
+  mapping_1 = (int *)xxmalloc(sizeof(int)*(sigmasizes+3));
+  mapping_2 = (int *)xxmalloc(sizeof(int)*(sigmasizes+3));
+
+  /* Fill mergesigma */
+
+  mergesigma = (struct mergesigma *)xxmalloc(sizeof(struct mergesigma));
+  mergesigma->number = -1;
+  mergesigma->symbol = NULL;
+  mergesigma->next = NULL;
+  start_mergesigma = mergesigma;
+
+  /* Loop over sigma 1, sigma 2 */
+  for (;;) {
+    if (sigma_1 == NULL)
+      end_1 = 1;
+    if (sigma_2 == NULL)
+      end_2 = 1;
+    if (end_1 && end_2)
+      break;
+    if (end_2) {
+      /* Treating only 1 now */
+      mergesigma = add_to_mergesigma(mergesigma, sigma_1, 1);
+      *(mapping_1+(sigma_1->number)) = mergesigma->number;
+      sigma_1 = sigma_1->next;
+      equal = 0;
+      continue;
+    }
+    else if (end_1) {
+      /* Treating only 2 now */
+      mergesigma = add_to_mergesigma(mergesigma, sigma_2, 2);
+      *(mapping_2+(sigma_2->number)) = mergesigma->number;
+      sigma_2 = sigma_2->next;
+      equal = 0;
+      continue;
+    }
+
+    else {
+
+      /* Both alive */
+
+      /* 1 or 2 contains special characters */
+      if ((sigma_1->number <= IDENTITY) || (sigma_2->number <= IDENTITY)) {
+
+	/* Treating zeros or unknowns */
+	
+	if ((sigma_1->number == UNKNOWN) || (sigma_1->number == IDENTITY))
+	  unknown_1 = 1;
+	if ((sigma_2->number == UNKNOWN) || (sigma_2->number == IDENTITY))
+	  unknown_2 = 1;
+
+	if (sigma_1->number == sigma_2->number) {
+	  mergesigma = add_to_mergesigma(mergesigma, sigma_1, 3);
+	  sigma_1 = sigma_1->next;
+	  sigma_2 = sigma_2->next;
+	}
+	else if (sigma_1->number < sigma_2->number) {
+	  mergesigma = add_to_mergesigma(mergesigma, sigma_1, 1);
+	  sigma_1 = sigma_1->next;
+	  equal = 0;
+	}
+	else {
+	  mergesigma = add_to_mergesigma(mergesigma, sigma_2, 2);
+	  sigma_2 = sigma_2->next;
+	  equal = 0;
+	}
+	continue;
+      }
+      /* Both contain non-special chars */
+      if (strcmp(sigma_1->symbol, sigma_2->symbol) == 0) {
+        mergesigma = add_to_mergesigma(mergesigma, sigma_1, 3);
+	/* Add symbol numbers to mapping */
+	*(mapping_1+(sigma_1->number)) = mergesigma->number;
+	*(mapping_2+(sigma_2->number)) = mergesigma->number;
+
+	sigma_1 = sigma_1->next;
+	sigma_2 = sigma_2->next;
+      }
+      else if (strcmp(sigma_1->symbol, sigma_2->symbol) < 0) {
+	mergesigma = add_to_mergesigma(mergesigma, sigma_1, 1);
+	*(mapping_1+(sigma_1->number)) = mergesigma->number;
+	sigma_1 = sigma_1->next;
+	equal = 0;
+      }
+      else {
+	mergesigma = add_to_mergesigma(mergesigma, sigma_2, 2);
+	*(mapping_2+(sigma_2->number)) = mergesigma->number;
+	sigma_2 = sigma_2->next;
+	equal = 0;
+      }
+      continue;
+    }
+  }
+  
+  /* Go over both net1 and net2 and replace arc numbers with new mappings */
+  
+  fsm_state = net1->states;
+  for (i=0; (fsm_state+i)->state_no != -1; i++) {
+    if ((fsm_state+i)->in > 2)
+      (fsm_state+i)->in = *(mapping_1+(fsm_state+i)->in);
+    if ((fsm_state+i)->out > 2)
+      (fsm_state+i)->out = *(mapping_1+(fsm_state+i)->out);
+  }
+  fsm_state = net2->states;
+  for (i=0; (fsm_state+i)->state_no != -1; i++) {
+    if ((fsm_state+i)->in > 2)
+      (fsm_state+i)->in = *(mapping_2+(fsm_state+i)->in);
+    if ((fsm_state+i)->out > 2)
+      (fsm_state+i)->out = *(mapping_2+(fsm_state+i)->out);
+  }
+
+  /* Copy mergesigma to net1, net2 */
+  
+  new_sigma_1 = copy_mergesigma(start_mergesigma);
+  new_sigma_2 = copy_mergesigma(start_mergesigma);
+  
+  fsm_sigma_destroy(net1->sigma);
+  fsm_sigma_destroy(net2->sigma);
+
+  net1->sigma = new_sigma_1;
+  net2->sigma = new_sigma_2;
+
+  /* Expand on ?, ?:x, y:? */
+
+  if (unknown_1 && !equal) {
+    /* Expand net 1 */
+    fsm_state = net1->states;
+    net_lines = find_arccount(net1->states);
+    for(mergesigma = start_mergesigma; mergesigma != NULL; mergesigma=mergesigma->next) {
+      if(mergesigma->presence == 2) {
+	net_unk++;
+      }
+    }
+    for(net_adds = 0, i=0; (fsm_state+i)->state_no != -1; i++) {
+      if ((fsm_state+i)->in == IDENTITY)
+	net_adds += net_unk;
+      if (((fsm_state+i)->in == UNKNOWN) && ((fsm_state+i)->out != UNKNOWN))
+	net_adds += net_unk;
+      if (((fsm_state+i)->out == UNKNOWN) && ((fsm_state+i)->in != UNKNOWN))
+	net_adds += net_unk;
+      if (((fsm_state+i)->in == UNKNOWN) && ((fsm_state+i)->out == UNKNOWN))
+	net_adds += net_unk*net_unk - net_unk + 2*net_unk;
+    }
+
+    new_1_state = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(net_adds+net_lines+1));
+    for(i=0,j=0; (fsm_state+i)->state_no != -1; i++) {
+      
+      if ((fsm_state+i)->in == IDENTITY) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma != NULL; mergesigma=mergesigma->next) {
+	  if ((mergesigma->presence == 2) && (mergesigma->number > IDENTITY)) {
+	    add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, mergesigma->number, mergesigma->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      if ((fsm_state+i)->in == UNKNOWN && (fsm_state+i)->out != UNKNOWN) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	  if ((mergesigma->presence == 2) && (mergesigma->number > IDENTITY)) {
+	    add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, mergesigma->number, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      if (((fsm_state+i)->in != UNKNOWN) && ((fsm_state+i)->out == UNKNOWN)) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma != NULL; mergesigma = mergesigma->next) {
+	  if ((mergesigma->presence == 2) && (mergesigma->number > IDENTITY)) {
+	    add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, mergesigma->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      /* Replace ?:? with ?:[all unknowns] [all unknowns]:? and [all unknowns]:[all unknowns] where a != b */
+      if ((fsm_state+i)->in == UNKNOWN && (fsm_state+i)->out == UNKNOWN) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma2=start_mergesigma; mergesigma2 != NULL ; mergesigma2 = mergesigma2->next) {
+	  for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	    if (((mergesigma->presence == 2 && mergesigma2->presence == 2 && mergesigma->number > IDENTITY && mergesigma2->number > IDENTITY) || (mergesigma->number == UNKNOWN && mergesigma2->number > IDENTITY && mergesigma2->presence == 2) || (mergesigma2->number == UNKNOWN && mergesigma->number > IDENTITY && mergesigma->presence == 2)) && mergesigma->number != mergesigma2->number) {
+	      add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, mergesigma->number, mergesigma2->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	      j++;
+	    }
+	  }
+	}
+      }
+
+      /* Simply copy arcs that are not IDENTITY or UNKNOWN */
+      if (((fsm_state+i)->in > IDENTITY || (fsm_state+i)->in == EPSILON) && ((fsm_state+i)->out > IDENTITY || (fsm_state+i)->out == EPSILON)) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+      }
+      
+      if ((fsm_state+i)->in == -1) {
+	add_fsm_arc(new_1_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+      }
+    }
+
+    add_fsm_arc(new_1_state, j, -1, -1, -1, -1, -1, -1);
+    xxfree(net1->states);
+    net1->states = new_1_state;
+  }
+
+  if (unknown_2 && !equal) {
+    /* Expand net 2 */
+    fsm_state = net2->states;
+    net_lines = find_arccount(net2->states);
+    for(net_unk = 0, mergesigma = start_mergesigma; mergesigma != NULL; mergesigma=mergesigma->next) {
+      if(mergesigma->presence == 1) {
+	net_unk++;
+      }
+    }
+
+    for(net_adds = 0, i=0; (fsm_state+i)->state_no != -1; i++) {
+      if ((fsm_state+i)->in == IDENTITY)
+	net_adds += net_unk;
+      if (((fsm_state+i)->in == UNKNOWN) && ((fsm_state+i)->out != UNKNOWN))
+	net_adds += net_unk;
+      if (((fsm_state+i)->out == UNKNOWN) && ((fsm_state+i)->in != UNKNOWN))
+	net_adds += net_unk;
+      if (((fsm_state+i)->in == UNKNOWN) && ((fsm_state+i)->out == UNKNOWN))
+	net_adds += net_unk*net_unk - net_unk + 2*net_unk;
+    }
+
+    /* We need net_add new lines in fsm_state */
+    new_2_state = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(net_adds+net_lines+1));
+    for(i=0,j=0; (fsm_state+i)->state_no != -1; i++) {
+
+      if ((fsm_state+i)->in == IDENTITY) {
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	  if ((mergesigma->presence == 1) && (mergesigma->number > IDENTITY)) {
+	    add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, mergesigma->number, mergesigma->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      if ((fsm_state+i)->in == UNKNOWN && (fsm_state+i)->out != UNKNOWN) {
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	  if (mergesigma->presence == 1 && mergesigma->number > IDENTITY) {
+	    add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, mergesigma->number, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      if ((fsm_state+i)->in != UNKNOWN && (fsm_state+i)->out == UNKNOWN) {
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	  if ((mergesigma->presence == 1) && (mergesigma->number > IDENTITY)) {
+	    add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, mergesigma->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	    j++;
+	  }
+	}
+      }
+
+      if ((fsm_state+i)->in == UNKNOWN && (fsm_state+i)->out == UNKNOWN) {
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+	for (mergesigma2=start_mergesigma; mergesigma2 != NULL ; mergesigma2 = mergesigma2->next) {
+	  for (mergesigma=start_mergesigma; mergesigma!=NULL; mergesigma=mergesigma->next) {
+	    if (((mergesigma->presence == 1 && mergesigma2->presence == 1 && mergesigma->number > IDENTITY && mergesigma2->number > IDENTITY) || (mergesigma->number == UNKNOWN && mergesigma2->number > IDENTITY && mergesigma2->presence == 1) || (mergesigma2->number == UNKNOWN && mergesigma->number > IDENTITY && mergesigma->presence == 1)) && mergesigma->number != mergesigma2->number) {
+	      add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, mergesigma->number, mergesigma2->number, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	      j++;
+	    }
+	  }
+	}
+      }
+
+      /* Simply copy arcs that are not IDENTITY or UNKNOWN */
+      if (((fsm_state+i)->in > IDENTITY || (fsm_state+i)->in == EPSILON) && ((fsm_state+i)->out > IDENTITY || (fsm_state+i)->out == EPSILON)) {
+	
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+      }
+
+      if ((fsm_state+i)->in == -1) {
+	add_fsm_arc(new_2_state, j, (fsm_state+i)->state_no, (fsm_state+i)->in, (fsm_state+i)->out, (fsm_state+i)->target, (fsm_state+i)->final_state, (fsm_state+i)->start_state);
+	j++;
+      }
+    }
+
+    add_fsm_arc(new_2_state, j, -1, -1, -1, -1, -1, -1);
+    xxfree(net2->states);
+    net2->states = new_2_state;
+  }
+  xxfree(mapping_1);
+  xxfree(mapping_2);
+
+  /* Free structure */
+  for (mergesigma2 = NULL; start_mergesigma != NULL; ) {
+      mergesigma2 = start_mergesigma;
+      start_mergesigma = start_mergesigma->next;
+      xxfree(mergesigma2);
+  }
+}
+
+
+int add_fsm_arc(struct fsm_state *fsm, int offset, int state_no, int in, int out, int target, int final_state, int start_state) {
+
+  (fsm+offset)->state_no = state_no;
+  (fsm+offset)->in = in;
+  (fsm+offset)->out= out;
+  (fsm+offset)->target = target;
+  (fsm+offset)->final_state = final_state;
+  (fsm+offset)->start_state = start_state;
+  offset++;
+  return(offset);
+}
+
+
+void fsm_count(struct fsm *net) {
+  struct fsm_state *fsm;
+  int i, linecount, arccount, oldstate, finalcount, maxstate;
+  linecount = arccount = finalcount = maxstate = 0;
+
+  oldstate = -1;
+
+  fsm = net->states;
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    if ((fsm+i)->state_no > maxstate)
+      maxstate = (fsm+i)->state_no;
+
+    linecount++;
+    if ((fsm+i)->target != -1) {
+        arccount++;
+	//        if (((fsm+i)->in != (fsm+i)->out) || ((fsm+i)->in == UNKNOWN) || ((fsm+i)->out == UNKNOWN))
+        //    arity = 2;
+    }
+    if ((fsm+i)->state_no != oldstate) {
+        if ((fsm+i)->final_state) {
+            finalcount++;
+        }
+        oldstate = (fsm+i)->state_no;
+    }
+  }
+
+  linecount++;
+  net->statecount = maxstate+1;
+  net->linecount = linecount;
+  net->arccount = arccount;
+  net->finalcount = finalcount;
+}
+
+static void fsm_add_to_states(struct fsm *net, int add) {
+  struct fsm_state *fsm;
+  int i;
+
+  fsm=net->states;
+  for(i=0; (fsm+i)->state_no != -1; i++) {
+    (fsm+i)->state_no = (fsm+i)->state_no + add;
+    if ((fsm+i)->target != -1)
+      (fsm+i)->target = (fsm+i)->target + add;
+  }
+}
+
+struct fsm *fsm_concat_m_n(struct fsm *net1, int m, int n) {
+  struct fsm *acc;
+    int i;
+    acc = fsm_empty_string();
+    for (i = 1; i <= n ;i++) {
+        if (i > m)
+            acc = fsm_concat(acc, fsm_optionality(fsm_copy(net1)));
+        else
+            acc = fsm_concat(acc, fsm_copy(net1));
+    }
+    fsm_destroy(net1);
+    return(acc);
+}
+
+struct fsm *fsm_concat_n(struct fsm *net1, int n) {
+    return(fsm_concat_m_n(net1,n,n));
+}
+
+struct fsm *fsm_concat(struct fsm *net1, struct fsm *net2) {
+  struct fsm_state *fsm1, *fsm2, *new_fsm;
+  int i,j,current_final;
+
+  fsm_merge_sigma(net1, net2);
+
+  fsm1 = net1->states;
+  fsm2 = net2->states;
+  fsm_count(net1);
+  fsm_count(net2);
+  /* The concatenation of a language with no final state should yield the empty language */
+  if ((net1->finalcount == 0) || (net2->finalcount == 0)) {
+      fsm_destroy(net1);
+      fsm_destroy(net2);
+      net1 = fsm_empty_set();
+      return(net1);
+  }
+
+  /* Add |fsm1| states to the state numbers of fsm2 */
+  fsm_add_to_states(net2, net1->statecount);
+
+  new_fsm = (struct fsm_state *)xxmalloc(((sizeof(struct fsm_state))*(net1->linecount + net2->linecount + net1->finalcount + 2 )));
+  current_final = -1;
+  /* Copy fsm1, fsm2 after each other, adding appropriate epsilon arcs */
+  for(i=0,j=0; (fsm1+i)->state_no != -1; i++) {
+    if (((fsm1+i)->final_state == 1) && ((fsm1+i)->state_no != current_final)) {
+      add_fsm_arc(new_fsm, j, (fsm1+i)->state_no, EPSILON, EPSILON, net1->statecount, 0, (fsm1+i)->start_state);
+      current_final = (fsm1+i)->state_no;
+      j++;
+    }
+    if (!(((fsm1+i)->target == -1) && ((fsm1+i)->final_state == 1))) {
+      add_fsm_arc(new_fsm, j, (fsm1+i)->state_no, (fsm1+i)->in, (fsm1+i)->out, (fsm1+i)->target, 0, (fsm1+i)->start_state);
+      j++;
+    }
+  }
+
+  for(i=0; (fsm2+i)->state_no != -1; i++, j++) {
+    add_fsm_arc(new_fsm, j, (fsm2+i)->state_no, (fsm2+i)->in, (fsm2+i)->out, (fsm2+i)->target, (fsm2+i)->final_state, 0);
+  }
+  add_fsm_arc(new_fsm, j, -1, -1, -1, -1, -1, -1);
+  xxfree(net1->states);
+  fsm_destroy(net2);
+  net1->states = new_fsm;
+  if (sigma_find_number(EPSILON, net1->sigma) == -1) {
+    sigma_add_special(EPSILON, net1->sigma);
+  }
+  fsm_count(net1);
+  net1->is_epsilon_free = NO;
+  net1->is_deterministic = NO;
+  net1->is_minimized = NO;
+  net1->is_pruned = NO;
+  return(fsm_minimize(net1));
+}
+
+struct fsm *fsm_union(struct fsm *net1, struct fsm *net2) {
+    struct fsm_state *new_fsm, *fsm1, *fsm2;
+    int i, j, net1_offset, net2_offset, new_target, arccount;
+    
+    fsm_merge_sigma(net1, net2);
+
+    fsm_count(net1);
+    fsm_count(net2);
+
+    fsm1 = net1->states;
+    fsm2 = net2->states;
+
+    net1_offset = 1;
+    net2_offset = net1->statecount + 1;
+    new_fsm = (struct fsm_state *)xxmalloc((net1->linecount + net2->linecount + 2) * sizeof(struct fsm_state));
+
+    j = 0;
+
+    add_fsm_arc(new_fsm, j++, 0, EPSILON, EPSILON, net1_offset, 0 , 1);
+    add_fsm_arc(new_fsm, j++, 0, EPSILON, EPSILON, net2_offset, 0 , 1);
+    arccount = 2;
+    for (i=0 ; (fsm1+i)->state_no != -1; i++) {
+        new_target = (fsm1+i)->target == -1 ? -1 : (fsm1+i)->target + net1_offset;
+        add_fsm_arc(new_fsm, j++, (fsm1+i)->state_no + net1_offset, (fsm1+i)->in, (fsm1+i)->out, new_target, (fsm1+i)->final_state, 0);
+        if (new_target != -1) arccount++;
+    }
+    for (i=0 ; (fsm2+i)->state_no != -1; i++) {
+        new_target = (fsm2+i)->target == -1 ? -1 : (fsm2+i)->target + net2_offset;
+        add_fsm_arc(new_fsm, j++, (fsm2+i)->state_no + net2_offset, (fsm2+i)->in, (fsm2+i)->out, new_target, (fsm2+i)->final_state, 0);
+        if (new_target != -1) arccount++;
+    }
+    add_fsm_arc(new_fsm, j++, -1, -1, -1, -1, -1, -1);
+    xxfree(net1->states);
+    net1->states = new_fsm;
+    net1->statecount = net1->statecount + net2->statecount + 1;
+    net1->linecount = j;
+    net1->arccount = arccount;
+    net1->finalcount = net1->finalcount + net2->finalcount;
+    fsm_destroy(net2);
+    fsm_update_flags(net1,NO,NO,NO,NO,UNK,NO);
+    if (sigma_find_number(EPSILON, net1->sigma) == -1) {
+        sigma_add_special(EPSILON, net1->sigma);
+    }
+    return(net1);
+}
+
+struct fsm *fsm_completes(struct fsm *net, int operation) {
+  struct fsm_state *fsm, *new_fsm;
+  int i, j, offset, statecount, sigsize, *state_table, sink_state, target, last_sigma = 0, arccount = 0, incomplete;
+  short int *starts, *finals, *sinks;
+  
+  /* TODO: this currently relies on that the sigma is gap-free in its numbering  */
+  /* which can't always be counted on, especially when reading external machines */
+
+  /* TODO: check arity */
+
+  if (net->is_minimized != YES)
+      net = fsm_minimize(net);
+
+  incomplete = 0;
+  fsm = net->states;
+  if (sigma_find_number(UNKNOWN, net->sigma) != -1) {
+      sigma_remove("@_UNKNOWN_SYMBOL_@",net->sigma);
+  }
+  if (sigma_find_number(IDENTITY, net->sigma) == -1) {
+    sigma_add_special(IDENTITY, net->sigma);
+    incomplete = 1;
+  }
+
+  sigsize = sigma_size(net->sigma);
+  last_sigma = sigma_max(net->sigma);
+
+  if (sigma_find_number(EPSILON, net->sigma) != -1)
+      sigsize--;
+
+  fsm_count(net);
+  statecount = net->statecount;
+  starts = (short *)xxmalloc(sizeof(short)*(statecount+1)); /* +1 for sink state */
+  finals = (short *)xxmalloc(sizeof(short)*(statecount+1));
+  sinks = (short *)xxmalloc(sizeof(short)*(statecount+1));
+
+  /* Init starts, finals, sinks arrays */
+
+  for (i=0; i < statecount; i++) {
+    *(sinks+i) = 1;
+    *(finals+i) = 0;
+    *(starts+i) = 0;
+  }
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    if (operation == COMPLEMENT) {
+      if ((fsm+i)->final_state == 1) {
+	(fsm+i)->final_state = 0;
+      } else if ((fsm+i)->final_state == 0) {
+	(fsm+i)->final_state = 1;
+      }
+    }
+    if ((fsm+i)->target != -1)
+      arccount++;
+    starts[(fsm+i)->state_no] = (fsm+i)->start_state;
+    finals[(fsm+i)->state_no] = (fsm+i)->final_state;
+    if ((fsm+i)->final_state && operation != COMPLEMENT)
+      *(sinks+((fsm+i)->state_no)) = 0;
+    if ((fsm+i)->final_state == 0 && (operation == COMPLEMENT))
+      *(sinks+((fsm+i)->state_no)) = 0;
+    if (((fsm+i)->target != -1) && ((fsm+i)->state_no != (fsm+i)->target))
+      *(sinks+((fsm+i)->state_no)) = 0;
+  }
+
+  net->is_loop_free = NO;
+  net->pathcount = PATHCOUNT_CYCLIC;
+
+  if (incomplete == 0 && (arccount == (sigsize)*statecount)) {
+    /*    printf("Already complete!\n"); */
+
+/*     if (operation == COMPLEMENT) { */
+/*       for (i=0; (fsm+i)->state_no != -1; i++) { */
+/* 	if ((fsm+i)->final_state) { */
+/* 	  (fsm+i)->final_state = 0; */
+/* 	} else { */
+/* 	  (fsm+i)->final_state = 1; */
+/* 	} */
+/*       } */
+/*     } */
+    xxfree(starts);
+    xxfree(finals);
+    xxfree(sinks);
+    net->is_completed = YES;
+    net->is_minimized = YES;
+    net->is_pruned = NO;
+    net->is_deterministic = YES;
+    return(net);
+  }
+
+  /* Find an existing sink state, or invent a new one */
+
+  for (i=0, sink_state = -1; i<statecount; i++) {
+    if (sinks[i] == 1) {
+      sink_state = i;
+      break;
+    }
+  }
+
+  if (sink_state == -1) {
+    sink_state = statecount;
+    *(starts+sink_state) = 0;
+    if (operation == COMPLEMENT) {
+      *(finals+sink_state) = 1;
+    } else {
+      *(finals+sink_state) = 0;
+    }
+    statecount++;
+  }
+
+
+  /* We can build a state table without memory problems since the size */
+  /* of the completed machine will be |Sigma| * |States| in all cases */
+
+  sigsize += 2;
+
+  state_table = (int *)xxmalloc(sizeof(int)*sigsize*statecount);
+
+  /* Init state table */
+  /* i = state #, j = sigma # */
+  for (i=0; i<statecount; i++) {
+    for (j=0; j<sigsize; j++) {
+      *(state_table+(i*sigsize+j)) = -1;
+    }
+  }
+  
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    if ((fsm+i)->target != -1) {
+      *(state_table+(((fsm+i)->state_no)*sigsize+((fsm+i)->in))) = (fsm+i)->target;
+    }
+  }
+  /* Add looping arcs from and to sink state */
+  for (j=2; j<=last_sigma; j++)
+      *(state_table+(sink_state*sigsize+j)) = sink_state;
+  /* Add missing arcs to sink state from all states */
+  for (i=0; i<statecount; i++) {
+    for (j=2; j<=last_sigma; j++) {
+      if (*(state_table+(i*sigsize+j)) == -1)
+	*(state_table+(i*sigsize+j)) = sink_state;
+    }
+  }
+  
+  new_fsm = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(sigsize*statecount+1));
+  
+/* Complement requires toggling final, nonfinal states */
+/*   if (operation == COMPLEMENT) */
+/*     for (i=0; i < statecount; i++) */
+/*       *(finals+i) = *(finals+i) == 0 ? 1 : 0; */
+  
+  for (i=0, offset = 0; i<statecount; i++) {
+    for (j=2; j<=last_sigma; j++) {
+      target = *(state_table+(i*sigsize+j)) == -1 ? sink_state : *(state_table+(i*sigsize+j));
+      add_fsm_arc(new_fsm, offset, i, j, j, target, finals[i], starts[i]);
+      offset++;
+    }
+  }
+  add_fsm_arc(new_fsm, offset, -1, -1, -1, -1, -1, -1);
+  offset++;
+  xxfree(net->states);
+  net->states = new_fsm;
+  xxfree(starts);
+  xxfree(finals);
+  xxfree(sinks);
+  xxfree(state_table);
+  net->is_minimized = NO;
+  net->is_pruned = NO;
+  net->is_completed = YES;
+  net->statecount = statecount;
+  return(net);
+}
+
+struct fsm *fsm_complete(struct fsm *net) {
+  return(fsm_completes(net, COMPLETE));
+}
+
+struct fsm *fsm_complement(struct fsm *net) {
+  return(fsm_completes(net, COMPLEMENT));
+}
+
+struct fsm *fsm_kleene_closure(struct fsm *net, int operation) {
+    struct fsm_state *fsm, *new_fsm;
+    int i, j, laststate, curr_state, curr_target, arccount;
+
+    if (operation == OPTIONALITY) {
+        return(fsm_union(net,fsm_empty_string()));
+    }
+
+    net = fsm_minimize(net);
+    fsm_count(net);
+
+    fsm = net->states;
+    
+    new_fsm = (struct fsm_state *)xxmalloc( (net->linecount + net->finalcount + 1) * sizeof(struct fsm_state));
+
+    j = 0;
+    if (operation == KLEENE_STAR)
+        add_fsm_arc(new_fsm, j++, 0, EPSILON, EPSILON, 1, 1, 1);
+    if (operation == KLEENE_PLUS)
+        add_fsm_arc(new_fsm, j++, 0, EPSILON, EPSILON, 1, 0, 1);
+    laststate = 0;
+    arccount = 1;
+    for (i = 0 ; (fsm+i)->state_no != -1; i++, laststate = curr_state) {
+        curr_state = (fsm+i)->state_no + 1;
+        curr_target = (fsm+i)->target == -1 ? -1 : (fsm+i)->target + 1;
+        if (curr_target == -1 && (fsm+i)->final_state == 1) {
+            add_fsm_arc(new_fsm, j++, curr_state, EPSILON, EPSILON, 0, 1, 0);
+            arccount++;
+            continue;
+        }
+        if (curr_state != laststate && (fsm+i)->final_state == 1) {
+            arccount++;
+            add_fsm_arc(new_fsm, j++, curr_state, EPSILON, EPSILON, 0, 1, 0);
+        }
+        add_fsm_arc(new_fsm, j++, curr_state, (fsm+i)->in, (fsm+i)->out, curr_target, (fsm+i)->final_state, 0);
+        if (curr_target != -1) arccount++;
+    }
+    add_fsm_arc(new_fsm, j++, -1,-1,-1,-1,-1,-1);
+    net->statecount = net->statecount+1;
+    net->linecount = j;
+    net->finalcount = operation == KLEENE_STAR ? net->finalcount+1 : net->finalcount;
+    net->arccount = arccount;
+    net->pathcount = PATHCOUNT_UNKNOWN;
+    xxfree(net->states);
+    net->states = new_fsm;
+    if (sigma_find_number(EPSILON, net->sigma) == -1)
+        sigma_add_special(EPSILON, net->sigma);
+    fsm_update_flags(net,NO,NO,NO,NO,UNK,NO);
+    return(net);
+}
+
+char *fsm_network_to_char(struct fsm *net) {
+    struct sigma *sigma, *sigprev;
+    sigma = net->sigma;
+    if (sigma->number == -1) {
+        return NULL;
+    }
+    for (; sigma != NULL && sigma->number != -1 ; sigma = sigma->next) {
+	sigprev = sigma;
+    }
+    return(xxstrdup(sigprev->symbol));
+}
+
+struct fsm *fsm_substitute_label(struct fsm *net, char *original, struct fsm *substitute) {
+   
+    struct fsm *outnet, *subnet2;
+    struct fsm_read_handle *inh, *subh, *subh2;
+    struct fsm_construct_handle *outh;
+    char *subin, *subout;
+    int i, repsym, source, target, in, out, addstate1, addstate2;
+        
+    fsm_merge_sigma(net, substitute);
+    addstate1 = net->statecount;
+    addstate2 = substitute->statecount;
+
+    inh = fsm_read_init(net);
+    subh = fsm_read_init(substitute);
+    repsym = fsm_get_symbol_number(inh, original);
+    if (repsym == -1) {
+	fsm_read_done(inh);
+	return(net);
+    }
+    outh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(outh, net->sigma);
+    while (fsm_get_next_arc(inh)) {
+	source = fsm_get_arc_source(inh);
+	target = fsm_get_arc_target(inh);
+	in = fsm_get_arc_num_in(inh);
+	out = fsm_get_arc_num_out(inh);
+
+	/* Double-sided arc, splice in substitute network */
+	if (in == repsym && out == repsym) {
+	    fsm_read_reset(subh);
+	    fsm_construct_add_arc_nums(outh, source, addstate1, EPSILON, EPSILON);
+	    while (fsm_get_next_arc(subh)) {
+		source = fsm_get_arc_source(subh);
+		target = fsm_get_arc_target(subh);
+		subin = fsm_get_arc_in(subh);
+		subout = fsm_get_arc_out(subh);
+		fsm_construct_add_arc(outh, source+addstate1, target+addstate1, subin, subout);
+	    }
+	    while ((i = fsm_get_next_final(subh)) != -1) {
+		target = fsm_get_arc_target(inh);
+		fsm_construct_add_arc_nums(outh, addstate1+i, target, EPSILON, EPSILON);
+	    }
+	    addstate1 = addstate1 + addstate2;
+	    /* One-sided replace, splice in repsym .x. sub or sub .x. repsym */
+	} else if (in == repsym || out == repsym) {
+	    if (in == repsym) {
+		subnet2 = fsm_minimize(fsm_cross_product(fsm_copy(substitute), fsm_symbol(fsm_get_arc_out(inh))));
+	    } else {
+		subnet2 = fsm_minimize(fsm_cross_product(fsm_symbol(fsm_get_arc_in(inh)),fsm_copy(substitute)));
+	    }
+	    fsm_construct_add_arc_nums(outh, source, addstate1, EPSILON, EPSILON);
+	    subh2 = fsm_read_init(subnet2);
+	    while (fsm_get_next_arc(subh2)) {
+		source = fsm_get_arc_source(subh2);
+		target = fsm_get_arc_target(subh2);
+		subin = fsm_get_arc_in(subh2);
+		subout = fsm_get_arc_out(subh2);
+		fsm_construct_add_arc(outh, source+addstate1, target+addstate1, subin, subout);
+	    }
+	    while ((i = fsm_get_next_final(subh2)) != -1) {
+		target = fsm_get_arc_target(inh);
+		fsm_construct_add_arc_nums(outh, addstate1+i, target, EPSILON, EPSILON);
+	    }
+	    fsm_read_done(subh2);
+	    addstate1 = addstate1 + subnet2->statecount;
+	    fsm_destroy(subnet2);
+	} else {
+	    /* Default, just copy arc */
+	    fsm_construct_add_arc_nums(outh, source, target, in, out);
+	}
+    }
+
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(outh, i);
+    }
+    while ((i = fsm_get_next_initial(inh)) != -1) {
+	fsm_construct_set_initial(outh, i);
+    }
+    fsm_read_done(inh);
+    fsm_read_done(subh);
+    outnet = fsm_construct_done(outh);
+    return(outnet);
+}
+
+struct fsm *fsm_substitute_symbol(struct fsm *net, char *original, char *substitute) {
+    struct fsm_state *fsm;
+    int i,o,s = EPSILON;
+    if (strcmp(original,substitute) == 0)
+        return(net);
+    if ((o = sigma_find(original, net->sigma)) == -1) {
+	//fprintf(stderr, "\nSymbol '%s' not found in network!\n", original);
+	return(net);
+    }
+    if (strcmp(substitute,"0") == 0)
+        s = EPSILON;
+    else if (substitute != NULL && (s = sigma_find(substitute, net->sigma)) == -1) {
+        s = sigma_add(substitute, net->sigma);
+    }
+    for (i=0, fsm = net->states; (fsm+i)->state_no != -1; i++) {
+	if ((fsm+i)->in == o) {
+	    (fsm+i)->in = s;
+        }
+	if ((fsm+i)->out == o) {
+	    (fsm+i)->out = s;
+        }
+    }
+    net->sigma = sigma_remove(original, net->sigma);
+    sigma_sort(net);
+    fsm_update_flags(net, NO, NO, NO, NO, NO, NO);
+    sigma_cleanup(net,0);
+    /* if s = epsilon */
+    net->is_minimized = NO;
+    return(fsm_determinize(net));
+}
+
+struct fsm *fsm_cross_product(struct fsm *net1, struct fsm *net2) {
+  int i, a, b, current_state, current_start, current_final, target_number, symbol1, symbol2, epsilon = 0, unknown = 0;
+  struct fsm_state *machine_a, *machine_b, *fsm;
+  struct state_arr *point_a, *point_b;
+  struct triplethash *th;
+
+  /* Perform a cross product by running two machines in parallel */
+  /* The approach here allows a state to stay, creating a a:0 or 0:b transition */
+  /* with the a/b-state waiting, and the arc going to {a,stay} or {stay,b} */
+  /* the wait maneuver is only possible if the waiting state is final */
+  
+  /* For the rewrite rules compilation, a different cross-product is used:  */
+  /* rewrite_cp() synchronizes A and B as long as possible to get a unique  */
+  /* output match for each cross product.                                   */
+
+  /* This behavior where we postpone zeroes on either side and perform */
+  /* and equal length cross-product as long as possible and never intermix */
+  /* ?:0 and 0:? arcs (i.e. we keep both machines synchronized as long as possible */
+  /* can be done by [A .x. B] & ?:?* [?:0*|0:?*] at the cost of possibly */
+  /* up to three times larger transducers. */
+  /* This is very similar to the idea in "tristate composition" in fsm_compose() */
+
+  /* This function is only used for explicit cross products */
+  /* such as a:b or A.x.B, etc.  In rewrite rules, we use rewrite_cp() */
+
+  net1 = fsm_minimize(net1);
+  net2 = fsm_minimize(net2);
+
+  fsm_merge_sigma(net1, net2);
+  
+  fsm_count(net1);
+  fsm_count(net2);
+
+  machine_a = net1->states;
+  machine_b = net2->states;
+  
+  /* new state 0 = {0,0} */
+
+  STACK_2_PUSH(0,0);
+
+  th = triplet_hash_init();
+  triplet_hash_insert(th, 0, 0, 0);
+
+  fsm_state_init(sigma_max(net1->sigma));
+
+  point_a = init_state_pointers(machine_a);
+  point_b = init_state_pointers(machine_b);
+
+  while (!int_stack_isempty()) {
+ 
+   /* Get a pair of states to examine */
+ 
+    a = int_stack_pop();
+    b = int_stack_pop();
+    
+   /* printf("Treating pair: {%i,%i}\n",a,b); */
+
+    current_state = triplet_hash_find(th, a, b, 0);
+    current_start = (((point_a+a)->start == 1) && ((point_b+b)->start == 1)) ? 1 : 0;
+    current_final = (((point_a+a)->final == 1) && ((point_b+b)->final == 1)) ? 1 : 0;
+
+    fsm_state_set_current_state(current_state, current_final, current_start);
+
+    for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a  ; machine_a++) {
+      for (machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+	
+	if ((machine_a->target == -1) && (machine_b->target == -1)) {
+	  continue;
+	}
+	if ((machine_a->target == -1) && (machine_a->final_state == 0)) {
+	  continue;
+	}
+	if ((machine_b->target == -1) && (machine_b->final_state == 0)) {
+	  continue;
+	}
+	/* Main check */
+	if (!((machine_a->target == -1) || (machine_b->target == -1))) {
+	    if ((target_number = triplet_hash_find(th, machine_a->target, machine_b->target, 0)) == -1) {
+              STACK_2_PUSH(machine_b->target, machine_a->target);
+              target_number = triplet_hash_insert(th, machine_a->target, machine_b->target, 0);
+	  }
+	  symbol1 = machine_a->in;
+	  symbol2 = machine_b->in;
+	  if (symbol1 == IDENTITY && symbol2 != IDENTITY)
+	    symbol1 = UNKNOWN;
+	  if (symbol2 == IDENTITY && symbol1 != IDENTITY)
+	    symbol2 = UNKNOWN;
+	  
+          fsm_state_add_arc(current_state, symbol1, symbol2, target_number, current_final, current_start);
+	  /* @:@ -> @:@ and also ?:? */
+	  if ((machine_a->in == IDENTITY) && (machine_b->in == IDENTITY)) {
+              fsm_state_add_arc(current_state, UNKNOWN, UNKNOWN, target_number, current_final, current_start);
+	  }
+	}
+	if (machine_a->final_state == 1 && machine_b->target != -1) {
+            
+	  /* Add 0:b i.e. stay in state A */
+	    if ((target_number = triplet_hash_find(th, machine_a->state_no, machine_b->target, 0)) == -1) {
+		STACK_2_PUSH(machine_b->target, machine_a->state_no);
+		target_number = triplet_hash_insert(th, machine_a->state_no, machine_b->target, 0);
+	    }
+	  /* @:0 becomes ?:0 */
+	  symbol2 = machine_b->in == IDENTITY ? UNKNOWN : machine_b->in;
+          fsm_state_add_arc(current_state, EPSILON, symbol2, target_number, current_final, current_start);
+	}
+
+	if (machine_b->final_state == 1 && machine_a->target != -1) {
+	  
+	  /* Add a:0 i.e. stay in state B */
+	    if ((target_number = triplet_hash_find(th, machine_a->target, machine_b->state_no, 0)) == -1) {
+              STACK_2_PUSH(machine_b->state_no, machine_a->target);
+              target_number = triplet_hash_insert(th, machine_a->target, machine_b->state_no, 0);
+	  }
+	  /* @:0 becomes ?:0 */
+	  symbol1 = machine_a->in == IDENTITY ? UNKNOWN : machine_a->in;
+          fsm_state_add_arc(current_state, symbol1, EPSILON, target_number, current_final, current_start);
+	}
+      }
+    }
+    /* Check arctrack */
+    fsm_state_end_state();
+  }
+  
+  xxfree(net1->states);
+  fsm_state_close(net1);
+
+  for (i=0, fsm = net1->states; (fsm+i)->state_no != -1; i++) {
+      if (((fsm+i)->in == EPSILON) || ((fsm+i)->out == EPSILON))
+          epsilon = 1;
+      if (((fsm+i)->in == UNKNOWN) || ((fsm+i)->out == UNKNOWN))
+          unknown = 1;
+  }
+  if (epsilon == 1) {
+      if (sigma_find_number(EPSILON, net1->sigma) == -1) {
+          sigma_add_special(EPSILON, net1->sigma);
+      }
+  }
+  if (unknown == 1) {
+      if (sigma_find_number(UNKNOWN, net1->sigma) == -1) {
+          sigma_add_special(UNKNOWN, net1->sigma);
+      }
+  }
+  xxfree(point_a);
+  xxfree(point_b);
+  fsm_destroy(net2);
+  triplet_hash_free(th);
+  return(fsm_coaccessible(net1));
+}
+
+struct fsm *fsm_precedes(struct fsm *net1, struct fsm *net2) {
+    return(fsm_complement(fsm_minimize(fsm_contains(fsm_minimize(fsm_concat(fsm_minimize(fsm_copy(net2)),fsm_concat(fsm_universal(),fsm_minimize(fsm_copy(net1)))))))));
+}
+
+struct fsm *fsm_follows(struct fsm *net1, struct fsm *net2) {
+    return(fsm_complement(fsm_minimize(fsm_contains(fsm_minimize(fsm_concat(fsm_minimize(fsm_copy(net1)),fsm_concat(fsm_universal(),fsm_minimize(fsm_copy(net2)))))))));
+}
+
+struct fsm *fsm_unflatten(struct fsm *net, char *epsilon_sym, char *repeat_sym) {
+    int a, b, current_state, current_start, current_final, target_number, epsilon, repeat, in, out;
+    struct fsm_state *even_state, *odd_state;
+    struct state_arr *point_a;
+    struct triplethash *th;
+    
+    fsm_minimize(net);
+    fsm_count(net);
+    
+    epsilon = sigma_find(epsilon_sym, net->sigma);
+    repeat = sigma_find(repeat_sym, net->sigma);
+    
+    even_state = net->states;
+    
+    /* new state 0 = {0,0} */
+    
+    STACK_2_PUSH(0,0);
+    
+    th = triplet_hash_init();
+    triplet_hash_insert(th, 0, 0, 0);
+    
+    fsm_state_init(sigma_max(net->sigma));
+    
+    point_a = init_state_pointers(even_state);
+
+    while (!int_stack_isempty()) {
+	
+	/* Get a pair of states to examine */
+	
+	a = int_stack_pop();
+	a = int_stack_pop();
+	
+	/* printf("Treating pair: {%i,%i}\n",a,b); */
+	
+	current_state = triplet_hash_find(th, a, a, 0);
+	current_start = ((point_a+a)->start == 1) ? 1 : 0;
+	current_final = ((point_a+a)->final == 1) ? 1 : 0;
+	
+	fsm_state_set_current_state(current_state, current_final, current_start);
+	
+	for (even_state = (point_a+a)->transitions; even_state->state_no == a; even_state++) {
+	    if (even_state->target == -1) {
+		continue;
+	    }
+	    in = even_state->in;
+	    b = even_state->target;
+	    for (odd_state = (point_a+b)->transitions; odd_state->state_no == b; odd_state++) {
+		if (odd_state->target == -1) {
+		    continue;
+		}
+		if ((target_number = triplet_hash_find(th, odd_state->target, odd_state->target, 0)) == -1) {
+		    STACK_2_PUSH(odd_state->target, odd_state->target);
+		    target_number = triplet_hash_insert(th, odd_state->target, odd_state->target, 0);
+		}
+		in = even_state->in;
+		out = odd_state->in;
+		if (out == repeat) {
+		    out = in;
+		} else if (in == IDENTITY || out == IDENTITY) {
+		    in = in == IDENTITY ? UNKNOWN : in;
+		    out = out == IDENTITY ? UNKNOWN : out;
+		}
+		if (in == epsilon) {
+		    in = EPSILON;
+		}
+		if (out == epsilon) {
+		    out = EPSILON;
+		}
+		fsm_state_add_arc(current_state, in, out, target_number, current_final, current_start);
+	    }
+	}
+	fsm_state_end_state();
+    }
+    xxfree(net->states);
+    fsm_state_close(net);
+    xxfree(point_a);
+    triplet_hash_free(th);
+    return(net);
+}
+
+
+struct fsm *fsm_shuffle(struct fsm *net1, struct fsm *net2) {
+  int a, b, current_state, current_start, current_final, target_number;
+  struct fsm_state *machine_a, *machine_b;
+  struct state_arr *point_a, *point_b;
+  struct triplethash *th;
+
+  /* Shuffle A and B by making alternatively A move and B stay at each or */
+  /* vice versa at each step */
+
+  fsm_minimize(net1);
+  fsm_minimize(net2);
+
+  fsm_merge_sigma(net1, net2);
+
+  fsm_count(net1);
+  fsm_count(net2);
+
+  machine_a = net1->states;
+  machine_b = net2->states;
+  
+  /* new state 0 = {0,0} */
+
+  STACK_2_PUSH(0,0);
+
+  th = triplet_hash_init();
+  triplet_hash_insert(th, 0, 0, 0);
+
+  fsm_state_init(sigma_max(net1->sigma));
+
+  point_a = init_state_pointers(machine_a);
+  point_b = init_state_pointers(machine_b);
+
+  while (!int_stack_isempty()) {
+ 
+   /* Get a pair of states to examine */
+ 
+    a = int_stack_pop();
+    b = int_stack_pop();
+    
+   /* printf("Treating pair: {%i,%i}\n",a,b); */
+
+    current_state = triplet_hash_find(th, a, b, 0);
+    current_start = (((point_a+a)->start == 1) && ((point_b+b)->start == 1)) ? 1 : 0;
+    current_final = (((point_a+a)->final == 1) && ((point_b+b)->final == 1)) ? 1 : 0;
+
+    fsm_state_set_current_state(current_state, current_final, current_start);
+
+    /* Follow A, B stays */
+    for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a  ; machine_a++) {
+	if (machine_a->target == -1) {
+	  continue;
+	}
+	if ((target_number = triplet_hash_find(th, machine_a->target, b, 0)) == -1) {
+          STACK_2_PUSH(b, machine_a->target);
+	  target_number = triplet_hash_insert(th, machine_a->target, b, 0);
+	}
+
+        fsm_state_add_arc(current_state, machine_a->in, machine_a->out, target_number, current_final, current_start);
+    }
+
+    /* Follow B, A stays */
+      for (machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+	
+	if (machine_b->target == -1) {
+	  continue;
+	}
+
+	if ((target_number = triplet_hash_find(th, a, machine_b->target, 0)) == -1) {
+              STACK_2_PUSH(machine_b->target, a);
+              target_number = triplet_hash_insert(th, a, machine_b->target, 0);
+	  }
+          fsm_state_add_arc(current_state, machine_b->in, machine_b->out, target_number, current_final, current_start);
+      }
+
+      /* Check arctrack */
+      fsm_state_end_state();
+  }
+
+  xxfree(net1->states);
+  fsm_state_close(net1);
+  xxfree(point_a);
+  xxfree(point_b);
+  fsm_destroy(net2);
+  triplet_hash_free(th);
+  return(net1);
+}
+
+int fsm_equivalent(struct fsm *net1, struct fsm *net2) {
+    /* Test path equivalence of two FSMs by traversing both in parallel */
+    int a, b, matching_arc, equivalent;
+    struct fsm_state *machine_a, *machine_b;
+    struct state_arr *point_a, *point_b;
+    struct triplethash *th;
+    
+    fsm_merge_sigma(net1, net2);
+    
+    fsm_count(net1);
+    fsm_count(net2);
+    
+    machine_a = net1->states;
+    machine_b = net2->states;
+    
+    equivalent = 0;
+    /* new state 0 = {0,0} */
+    STACK_2_PUSH(0,0);
+    
+    th = triplet_hash_init();
+    triplet_hash_insert(th, 0, 0, 0);
+    
+    point_a = init_state_pointers(machine_a);
+    point_b = init_state_pointers(machine_b);
+    
+    while (!int_stack_isempty()) {
+	
+	/* Get a pair of states to examine */
+	
+	a = int_stack_pop();
+	b = int_stack_pop();
+   	
+	if ((point_a+a)->final != (point_b+b)->final) {
+	    goto not_equivalent;
+	}
+	/* Check that all arcs in A have matching arc in B, push new state pair on stack */
+	for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a  ; machine_a++) {
+	    if (machine_a->target == -1) {
+		break;
+	    }
+	    matching_arc = 0;
+	    for (machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+		if (machine_b->target == -1) {
+		    break;
+		}
+		if (machine_a->in == machine_b->in && machine_a->out == machine_b->out) {
+		    matching_arc = 1;
+		    if ((triplet_hash_find(th, machine_a->target, machine_b->target, 0)) == -1) {
+			STACK_2_PUSH(machine_b->target, machine_a->target);
+			triplet_hash_insert(th, machine_a->target, machine_b->target, 0);
+		    }
+		    break;
+		}
+	    }
+	    if (matching_arc == 0) {
+		goto not_equivalent;
+	    }
+	}
+	for (machine_b = (point_b+b)->transitions; machine_b->state_no == b ; machine_b++) {
+	    if (machine_b->target == -1) {
+		break;
+	    }
+	    matching_arc = 0;
+	    for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a  ; machine_a++) {
+		if (machine_a->in == machine_b->in && machine_a->out == machine_b->out) {
+		    matching_arc = 1;
+		    break;
+		}
+	    }
+	    if (matching_arc == 0) {
+		goto not_equivalent;
+	    }
+	}
+    }
+    equivalent = 1;
+ not_equivalent:
+    fsm_destroy(net1);
+    fsm_destroy(net2);
+    xxfree(point_a);
+    xxfree(point_b);
+    triplet_hash_free(th);
+    return(equivalent);
+}
+
+
+struct fsm *fsm_minus(struct fsm *net1, struct fsm *net2) {
+    int a, b, current_state, current_start, current_final, target_number, b_has_trans, btarget, statecount;
+    struct fsm_state *machine_a, *machine_b;
+    struct state_arr *point_a, *point_b;
+    struct triplethash *th;
+    statecount = 0;
+
+    net1 = fsm_minimize(net1);
+    net2 = fsm_minimize(net2);
+    
+    fsm_merge_sigma(net1, net2);
+    
+    fsm_count(net1);
+    fsm_count(net2);
+    
+    machine_a = net1->states;
+    machine_b = net2->states;
+    
+    /* new state 0 = {1,1} */
+
+    int_stack_clear();
+    STACK_2_PUSH(1,1);
+
+    th = triplet_hash_init();
+    triplet_hash_insert(th, 1, 1, 0);
+
+    point_a = init_state_pointers(machine_a);
+    point_b = init_state_pointers(machine_b);
+
+    fsm_state_init(sigma_max(net1->sigma));
+
+  while (!int_stack_isempty()) {
+      statecount++;
+      /* Get a pair of states to examine */
+ 
+      a = int_stack_pop();
+      b = int_stack_pop();
+
+      current_state = triplet_hash_find(th, a, b, 0);
+      a--;
+      b--;
+    
+      if (b == -1) {
+          current_start = 0;
+          current_final = (point_a+a)->final;
+      } else {
+          current_start = (a == 0 && b == 0) ? 1 : 0;
+          current_final = (((point_a+a)->final == 1) && ((point_b+b)->final == 0)) ? 1 : 0;
+      }
+      
+      fsm_state_set_current_state(current_state, current_final, current_start);
+      
+      for (machine_a = (point_a+a)->transitions ; machine_a->state_no == a  ; machine_a++) {
+          if (machine_a->target == -1) {
+              break;
+              continue;
+          }
+          if (b == -1) {
+              /* b is dead */
+              if ((target_number = triplet_hash_find(th, (machine_a->target)+1, 0, 0)) == -1) {
+                  STACK_2_PUSH(0, (machine_a->target)+1);
+                  target_number = triplet_hash_insert(th, (machine_a->target)+1, 0, 0);
+              }
+          } else {
+              /* b is alive */
+              b_has_trans = 0;
+              for (machine_b = (point_b+b)->transitions ; machine_b->state_no == b ; machine_b++) {
+                  if (machine_a->in == machine_b->in && machine_a->out == machine_b->out) {
+                      b_has_trans = 1;
+                      btarget = machine_b->target;
+                      break;
+                  }
+              }
+              if (b_has_trans) {
+                  if ((target_number = triplet_hash_find(th, (machine_a->target)+1, btarget+1, 0)) == -1) {
+                      STACK_2_PUSH(btarget+1, (machine_a->target)+1);
+		      target_number = triplet_hash_insert(th, (machine_a->target)+1, (machine_b->target)+1, 0);
+                  }
+              } else {
+                  /* b is dead */
+                  if ((target_number = triplet_hash_find(th, (machine_a->target)+1, 0, 0)) == -1) {
+                      STACK_2_PUSH(0, (machine_a->target)+1);
+		      target_number = triplet_hash_insert(th, (machine_a->target)+1, 0, 0);
+                  }
+              }
+          }
+          fsm_state_add_arc(current_state, machine_a->in, machine_a->out, target_number, current_final, current_start);
+      }
+      fsm_state_end_state();
+  }
+  
+  xxfree(net1->states);
+  fsm_state_close(net1);
+  xxfree(point_a);
+  xxfree(point_b);
+  fsm_destroy(net2);
+  triplet_hash_free(th);
+  return(fsm_minimize(net1));
+}
+
+struct fsm *fsm_contains(struct fsm *net) {
+  /* [?* A ?*] */
+  struct fsm *net2;
+  
+  net2 = fsm_concat(fsm_concat(fsm_universal(),net),fsm_universal());
+  return(net2);
+}
+
+struct fsm *fsm_universal() {
+    struct fsm *net;
+    int s;
+    net = fsm_create("");
+    fsm_update_flags(net, YES, YES, YES, YES, NO, NO);
+    net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*2);
+    s = sigma_add_special(IDENTITY,net->sigma);
+    add_fsm_arc(net->states, 0, 0, s, s, 0, 1, 1);
+    add_fsm_arc(net->states, 1, -1, -1, -1, -1, -1, -1);
+    net->arccount = 1;
+    net->statecount = 1;
+    net->linecount = 2;
+    net->finalcount = 1;
+    net->pathcount = PATHCOUNT_CYCLIC;
+    return(net);
+}
+
+struct fsm *fsm_contains_one(struct fsm *net) {
+  /* $A - $[[?+ A ?* & A ?*] | [A ?+ & A]] */
+    struct fsm *ret;
+    ret = fsm_minus(fsm_contains(fsm_copy(net)),fsm_contains(fsm_union(fsm_intersect(fsm_concat(fsm_kleene_plus(fsm_identity()),fsm_concat(fsm_copy(net),fsm_universal())) , fsm_concat(fsm_copy(net),fsm_universal())),fsm_intersect(fsm_concat(fsm_copy(net),fsm_kleene_plus(fsm_identity())), fsm_copy(net)))));
+    fsm_destroy(net);
+    return(ret);
+}
+
+struct fsm *fsm_contains_opt_one(struct fsm *net) {
+  /* $.A | ~$A */
+    struct fsm *ret;
+    ret = fsm_union(fsm_contains_one(fsm_copy(net)),fsm_complement(fsm_contains(fsm_copy(net))));
+    fsm_destroy(net);
+    return(ret);
+}
+
+struct fsm *fsm_simple_replace(struct fsm *net1, struct fsm *net2) {
+  /* [~[?* [A-0] ?*] [A.x.B]]* ~[?* [A-0] ?*] */
+  
+    struct fsm *UPlus, *ret;
+    UPlus = fsm_minimize(fsm_kleene_plus(fsm_identity()));
+    ret = fsm_concat(fsm_minimize(fsm_kleene_star(fsm_minimize(fsm_concat(fsm_complement(fsm_minimize(fsm_concat(fsm_concat(fsm_universal(),fsm_minimize(fsm_intersect(fsm_copy(net1),fsm_copy(UPlus)))),fsm_universal()))),fsm_minimize(fsm_cross_product(fsm_copy(net1),fsm_copy(net2))))))),fsm_minimize(fsm_complement(fsm_minimize(fsm_concat(fsm_concat(fsm_universal(), fsm_intersect(fsm_copy(net1),fsm_copy(UPlus))),fsm_universal())))));
+    fsm_destroy(net1);
+    fsm_destroy(net2);
+    fsm_destroy(UPlus);
+    return(ret);
+}
+
+struct fsm *fsm_priority_union_upper(struct fsm *net1, struct fsm *net2) {
+    /* A .P. B = A | [~[A.u] .o. B] */
+    struct fsm *ret;
+    ret = fsm_union(fsm_copy(net1),fsm_compose(fsm_complement(fsm_upper(fsm_copy(net1))),net2));
+    fsm_destroy(net1);
+    return(ret);
+}
+
+struct fsm *fsm_priority_union_lower(struct fsm *net1, struct fsm *net2) {
+    /* A .p. B = A | B .o. ~[A.l] */
+    struct fsm *ret;
+    ret = fsm_union(fsm_copy(net1),fsm_compose(net2,fsm_complement(fsm_lower(fsm_copy(net1)))));
+    fsm_destroy(net1);
+    return(ret);
+}
+
+struct fsm *fsm_lenient_compose(struct fsm *net1, struct fsm *net2) {
+    /* A .O. B = [A .o. B] .P. B */
+    struct fsm *ret;
+    ret = fsm_priority_union_upper(fsm_compose(fsm_copy(net1),net2),fsm_copy(net1));
+    fsm_destroy(net1);
+    return(ret);
+}
+
+struct fsm *fsm_term_negation(struct fsm *net1) {
+    return(fsm_intersect(fsm_identity(),fsm_complement(net1)));
+}
+
+struct fsm *fsm_quotient_interleave(struct fsm *net1, struct fsm *net2) {
+    /* A/\/B = The set of strings you can interleave in B and get a string from A */
+    /* [B/[x \x* x] & A/x .o. [[[\x]:0]* (x:0 \x* x:0)]*].l */
+    struct fsm *Result;
+    Result = fsm_lower(fsm_compose(fsm_intersect(fsm_ignore(net2,fsm_concat(fsm_symbol("@>@"),fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol("@>@"))),fsm_symbol("@>@"))),OP_IGNORE_ALL),fsm_ignore(net1,fsm_symbol("@>@"),OP_IGNORE_ALL)),fsm_kleene_star(fsm_concat(fsm_kleene_star(fsm_cross_product(fsm_term_negation(fsm_symbol("@>@")),fsm_empty_string())),fsm_optionality(fsm_concat(fsm_cross_product(fsm_symbol("@>@"),fsm_empty_string()),fsm_concat(fsm_kleene_star(fsm_term_negation(f [...]
+
+    Result->sigma = sigma_remove("@>@",Result->sigma);
+    /* Could clean up sigma */
+    return(Result);
+}
+
+struct fsm *fsm_quotient_left(struct fsm *net1, struct fsm *net2) {
+    /* A\\\B = [B .o. A:0 ?*].l; */
+    /* A\\\B = the set of suffixes you can add to A to get a string in B */
+    struct fsm *Result;
+    Result = fsm_lower(fsm_compose(net2,fsm_concat(fsm_cross_product(net1,fsm_empty_string()),fsm_universal())));
+    return(Result);
+}
+
+struct fsm *fsm_quotient_right(struct fsm *net1, struct fsm *net2) {
+    struct fsm *Result;
+    
+    /* A///B = [A .o. ?* B:0].l; */
+    /* A///B = the set of prefixes you can add to B to get strings in A */
+    Result = fsm_lower(fsm_compose(net1, fsm_concat(fsm_universal(),fsm_cross_product(net2,fsm_empty_string()))));
+    return(Result);
+}
+
+struct fsm *fsm_ignore(struct fsm *net1, struct fsm *net2, int operation) {
+  struct fsm_state *fsm1, *fsm2, *new_fsm;
+  struct fsm *Result;
+  short int *handled_states1, *handled_states2;
+  int i, j, k, state_add_counter = 0, malloc_size, splices = 0, returns, target, splice_size, start_splice, states1, states2, lines1, lines2, *return_state;
+
+  net1 = fsm_minimize(net1);
+  net2 = fsm_minimize(net2);
+
+  if (fsm_isempty(net2)) {
+      fsm_destroy(net2);
+      return(net1);
+  }
+  fsm_merge_sigma(net1, net2);
+
+  fsm_count(net1);
+  fsm_count(net2);
+
+  states1 = net1->statecount;
+  states2 = net2->statecount;
+  lines1 = net1->linecount;
+  lines2 = net2->linecount;
+  fsm1 = net1->states;
+  fsm2 = net2->states;
+
+  if (operation == OP_IGNORE_INTERNAL) {
+    Result = fsm_lower(fsm_compose(fsm_ignore(fsm_copy(net1),fsm_symbol("@i<@"),OP_IGNORE_ALL),fsm_compose(fsm_complement(fsm_union(fsm_concat(fsm_symbol("@i<@"),fsm_universal()),fsm_concat(fsm_universal(),fsm_symbol("@i<@")))),fsm_simple_replace(fsm_symbol("@i<@"),fsm_copy(net2)))));
+    Result->sigma = sigma_remove("@i<@",Result->sigma);
+    fsm_destroy(net1);
+    fsm_destroy(net2);
+    return(Result);
+  }
+
+  malloc_size = lines1 + (states1 * (lines2 + net2->finalcount + 1));
+  new_fsm = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(malloc_size+1));
+
+  /* Mark if a state has been handled with ignore */
+  handled_states1 = (short *)xxmalloc(sizeof(short)*states1);
+  handled_states2 = (short *)xxmalloc(sizeof(short)*states2);
+
+  /* Mark which ignores return to which state */
+  return_state = (int *)xxmalloc(sizeof(int)*states1);
+  splice_size = states2;
+  start_splice = states1;
+  for (k=0; k<states1; k++)
+    *(handled_states1+k) = 0;
+ 
+  for (i=0, j=0; (fsm1+i)->state_no != -1; i++) {
+    if (*(handled_states1+(fsm1+i)->state_no) == 0) {
+      target =  start_splice + splices * splice_size;
+      add_fsm_arc(new_fsm, j, (fsm1+i)->state_no, EPSILON, EPSILON, target, (fsm1+i)->final_state, (fsm1+i)->start_state);
+      *(return_state+splices) = (fsm1+i)->state_no;
+      *(handled_states1+(fsm1+i)->state_no) = 1;
+      j++;
+      splices++;
+      if ((fsm1+i)->in != -1) {
+	add_fsm_arc(new_fsm, j, (fsm1+i)->state_no, (fsm1+i)->in, (fsm1+i)->out, (fsm1+i)->target, (fsm1+i)->final_state, (fsm1+i)->start_state);
+	j++;
+      }
+    } else {
+      add_fsm_arc(new_fsm, j, (fsm1+i)->state_no, (fsm1+i)->in, (fsm1+i)->out, (fsm1+i)->target, (fsm1+i)->final_state, (fsm1+i)->start_state);
+      j++;
+    }
+  }
+
+  /* Add a sequence of fsm2s at the end, with arcs back to the appropriate states */
+
+  state_add_counter = start_splice;
+
+  for (returns = 0; splices>0; splices--, returns++) {
+    /* Zero handled return arc states */
+
+    for (k=0; k<states2; k++)
+	 *(handled_states2+k) = 0;
+    
+    for (i=0; (fsm2+i)->state_no != -1; i++) {
+      if ((fsm2+i)->final_state == 1 && *(handled_states2+(fsm2+i)->state_no) == 0) {
+	add_fsm_arc(new_fsm, j, (fsm2+i)->state_no + state_add_counter, EPSILON, EPSILON, *(return_state+returns), 0, 0);
+	j++;
+	*(handled_states2+(fsm2+i)->state_no) = 1;
+	if ((fsm2+i)->target != -1) {
+	  add_fsm_arc(new_fsm, j, (fsm2+i)->state_no + state_add_counter, (fsm2+i)->in, (fsm2+i)->out , (fsm2+i)->target + state_add_counter, 0, 0);
+	  j++;
+	}
+      } else {
+	add_fsm_arc(new_fsm, j, (fsm2+i)->state_no + state_add_counter, (fsm2+i)->in, (fsm2+i)->out, (fsm2+i)->target + state_add_counter, 0, 0);
+	j++;
+      }
+    }
+    state_add_counter = state_add_counter + states2;
+  }
+
+  add_fsm_arc(new_fsm, j, -1, -1, -1, -1, -1, -1);
+  xxfree(handled_states1);
+  xxfree(handled_states2);
+  xxfree(return_state);
+  xxfree(net1->states);
+  fsm_destroy(net2);
+  net1->states = new_fsm;
+  fsm_update_flags(net1, NO, NO, NO, NO, NO, NO);
+  fsm_count(net1);
+  return(net1);
+}
+
+/* Remove those symbols from sigma that have the same distribution as IDENTITY */
+
+void fsm_compact(struct fsm *net) {
+    struct checktable {
+        int state_no;
+        int target;
+    } *checktable;
+
+    struct fsm_state *fsm;
+    struct sigma *sig, *sigprev, *sign;
+    Boolean *potential;
+    int i, j, prevstate, numsymbols, in, out, state, target, removable;
+
+    fsm = net->states;
+    numsymbols = sigma_max(net->sigma);
+    
+    potential = (bool *)xxmalloc(sizeof(Boolean)*(numsymbols+1));
+    checktable = (struct checktable *)xxmalloc(sizeof(struct checktable)*(numsymbols+1));
+
+    for (i=0; i <= numsymbols; i++) {
+        *(potential+i) =  1;
+        (checktable+i)->state_no = -1;
+        (checktable+i)->target = -1;
+    }
+    /* For consistency reasons, can't remove symbols longer than 1 */
+    /* since @ and ? only match utf8 symbols of length 1           */
+
+    for (sig = net->sigma; sig != NULL && sig->number != -1; sig = sig->next) {
+	if (utf8strlen(sig->symbol) > 1) {
+	    *(potential+sig->number) = 0;
+	}
+    }
+
+    prevstate = 0;
+
+    for (i=0;  ; i++) {
+
+        if ((fsm+i)->state_no != prevstate) {
+            for (j=3; j<=numsymbols;j++) {
+                if ((checktable+j)->state_no != prevstate && (checktable+IDENTITY)->state_no != prevstate) {
+                    continue;
+                }
+                if ((checktable+j)->target == (checktable+IDENTITY)->target && (checktable+j)->state_no == (checktable+IDENTITY)->state_no) {
+                    continue;
+                }
+                *(potential+j) = 0;
+            }
+        }
+
+        if ((fsm+i)->state_no == -1)
+            break;
+
+        in = (fsm+i)->in;
+        out = (fsm+i)->out;
+        state = (fsm+i)->state_no;
+        target = (fsm+i)->target;
+
+        if (in != -1 && out != -1) {
+            if (((in == out && in > 2) || in == IDENTITY)) {
+                (checktable+in)->state_no = state;
+                (checktable+in)->target = target;
+            }
+            if (in != out && in > 2) {
+                *(potential+in) = 0;
+            }
+            if (in != out && out > 2) {
+                *(potential+out) = 0;
+            }
+        }
+        prevstate = state;
+    }
+    for (removable = 0, i=3; i <= numsymbols; i++) {
+        if (*(potential+i) == 1) {
+            removable = 1;
+        }
+
+    }
+    if (removable == 0) {
+        xxfree(potential);
+        xxfree(checktable);
+        return;
+    }
+    i = j = 0;
+    do {
+        in = (fsm+i)->in;
+
+        add_fsm_arc(fsm, j ,(fsm+i)->state_no,(fsm+i)->in,(fsm+i)->out,(fsm+i)->target,(fsm+i)->final_state,(fsm+i)->start_state);
+        if (in == -1) {
+            i++;
+            j++;
+        }
+        else if (*(potential+in) == 1 && in > 2) {
+            i++;
+        } else {
+            i++;
+            j++;
+        }
+    } while ((fsm+i)->state_no != -1);
+    add_fsm_arc(fsm, j ,(fsm+i)->state_no,(fsm+i)->in,(fsm+i)->out,(fsm+i)->target,(fsm+i)->final_state,(fsm+i)->start_state);
+
+    sigprev = NULL;
+    for (sig = net->sigma; sig != NULL && sig->number != -1; sig = sign) {
+
+        if ((sig->number > 2) && (*(potential+sig->number) == 1)) {
+            sigprev->next = sig->next;
+            sign = sig->next;
+            xxfree(sig->symbol);
+            xxfree(sig);
+        } else {
+            sigprev = sig;
+            sign = sig->next;
+        }
+    }
+    xxfree(potential);
+    xxfree(checktable);
+    sigma_cleanup(net,0);
+}
+
+int fsm_symbol_occurs(struct fsm *net, char *symbol, int side) {
+    struct fsm_state *fsm;
+    int i, sym;
+    sym = sigma_find(symbol, net->sigma);
+    if (sym == -1) {
+        return 0;
+    }
+    for (i=0, fsm = net->states; (fsm+i)->state_no != -1; i++) {
+        if (side == M_UPPER && (fsm+i)->in == sym)
+            return 1;
+        if (side == M_LOWER && (fsm+i)->out == sym)
+            return 1;
+        if (side == (M_UPPER + M_LOWER) && ( (fsm+i)->in == sym || (fsm+i)->out == sym))
+            return 1;
+    }
+    return 0;
+}
+
+struct fsm *fsm_equal_substrings(struct fsm *net, struct fsm *left, struct fsm *right) {
+
+    /* The algorithm extracts from the lower side all and only those strings where   */
+    /* every X occurring in different substrings ... left X right ... is identical.  */
+
+    /* Caveat: there is no reliable termination condition for the loop that extracts */
+    /* identities.  This means that if run on languages where there are potentially  */
+    /* infinite-length identical delimited substrings, it will not terminate.        */
+
+    /* For example: _eq(l a* r l a* r, l , r) will not terminate.                    */
+
+    /* However, even if the languages occuring between left and right are infinite   */
+    /* the algorithm terminates eventually if the the possible combinations of       */
+    /* identical substrings is finite in length.                                     */
+
+    /* For example _eq([l a* b r l a b* r]*, l, r) does terminate even though        */
+    /* it contains a potentially infinite number of delimited substrings since       */
+    /* the maximum length of the possible identical delimited substrings is finite.  */
+
+    /* In this case the above example evaluates to the language [l a b r l a b r]*   */
+
+    /* The algorithm: */
+    /* Input: L, left, right */
+    /* Output: the language that preserves only those strings in L */
+    /*         where X is the same for all left X right sequences  */
+
+    /* 1. mark all instances of left with ... LB and right with RB ... in L   */
+
+    /* 2. split L into Leq and Lbypass                                        */
+    /*    where Lbypass are all those strings where LB RB sequences aren't    */
+    /*    properly nested (we must have ... LB ... RB ... LB ... RB ... etc.) */
+    /*    Lbypass also includes all those with less than two bracketed        */
+    /*    instances, since we don't need to check equality if there's only    */
+    /*    one bracketed substring.                                            */
+    /*    We also remove the auxiliary LB and RB symbols from Lbypass         */
+
+    /* 3. We extract all the possible symbols occurring between LB and RB     */
+    /*    from Leq                                                            */
+
+    /* 4. We create the transducer Move from all symbols in (3)               */
+    /*    Move = M(sym_1) | ... | M(sym_n)                                    */
+    /*    where M(a) is defined as [\LB* LB:a a:LB]* \LB*                     */
+    /*    i.e. it rewrites bracketed strings such as "LB a b RB LB a b RB"    */
+    /*    to "a LB b RB a LB b RB" in effect moving brackets to the right     */
+    /*    one step for a symbol.                                              */
+
+    /* 5. Leq = Cleanup(Leq)                                                  */
+    /*    Cleanup removes LB RB sequences and, at the same time filters out   */
+    /*    any strings where we find both LB RB and LB X RB where X is not 0.  */
+    /*    since we know such sequences could not possibly be identical        */
+    /*    Cleanup is implemented by composing Leq with                        */
+    /*    \LB* [LB:0 RB:0 \LB*]* | ~$[LB RB]                                  */
+    /*    - if the symbol LB does not occur on the lower side of Leq, goto(6) */
+    /*    - else Leq = Move(Leq), goto(5)                                     */
+
+    /* 6. Result = L .o. [Leq | Lbypass]                                      */
+
+    int syms;
+    struct sigma *sig;
+    struct fsm *LB, *RB, *NOLB, *NORB, *InsertBrackets, *RemoveBrackets, *Lbracketed, *NOBR, *BracketFilter, *Lbypass, *Leq, *Labels, *Cleanup, *ThisMove, *ThisSymbol, *Move, *Result, *oldnet;
+
+    oldnet = fsm_copy(net);
+
+    /* LB = "@<eq<@" */
+    /* RB = "@>eq>@" */
+    
+    LB = fsm_symbol("@<eq<@");
+    NOLB = fsm_minimize(fsm_term_negation(fsm_copy(LB)));
+    RB = fsm_symbol("@>eq>@");
+    NORB = fsm_minimize(fsm_term_negation(fsm_copy(RB)));
+    /* NOBR = ~$[LB|RB] */
+    NOBR = fsm_minimize(fsm_complement(fsm_contains(fsm_union(fsm_copy(LB),fsm_copy(RB)))));
+
+    sigma_add("@<eq<@", net->sigma);
+    sigma_add("@>eq>@", net->sigma);
+    sigma_sort(net);
+
+    /* Insert our aux markers into the language                */
+
+    /* InsertBrackets = [~$[L|R] [L 0:LB|0:RB R]]* ~$[L|R];    */
+
+    InsertBrackets = fsm_minimize(fsm_concat(fsm_kleene_star(fsm_concat(fsm_complement(fsm_contains(fsm_union(fsm_copy(left),fsm_copy(right)))),fsm_union(fsm_concat(fsm_copy(left),fsm_cross_product(fsm_empty_string(),fsm_copy(LB))),fsm_concat(fsm_cross_product(fsm_empty_string(),fsm_copy(RB)),fsm_copy(right))))),fsm_complement(fsm_contains(fsm_union(fsm_copy(left),fsm_copy(right))))));
+    
+
+    /* Lbracketed = L .o. InsertBrackets                       */
+
+    Lbracketed = fsm_compose(fsm_copy(net), InsertBrackets);
+
+    /* Filter out improper nestings, or languages with less than two marker pairs */
+
+    /* BracketFilter = NOBR LB NOBR RB NOBR [LB NOBR RB NOBR]+  */
+
+    BracketFilter = fsm_concat(fsm_copy(NOBR),fsm_concat(fsm_copy(LB),fsm_concat(fsm_copy(NOBR),fsm_concat(fsm_copy(RB),fsm_concat(fsm_copy(NOBR),fsm_kleene_plus(fsm_concat(fsm_copy(LB),fsm_concat(fsm_copy(NOBR),fsm_concat(fsm_copy(RB),fsm_copy(NOBR))))))))));
+
+    /* RemoveBrackets = [LB:0|RB:0|NOBR]*                       */
+    /* Lbypass = [Lbracketed .o. ~BracketFilter .o. LB|RB -> 0] */
+    /* Leq     = [Lbracketed .o.  BracketFilter]                */
+
+    RemoveBrackets = fsm_kleene_star(fsm_union(fsm_cross_product(fsm_copy(LB),fsm_empty_string()),fsm_union(fsm_cross_product(fsm_copy(RB),fsm_empty_string()),fsm_copy(NOBR))));
+
+
+    Lbypass = fsm_lower(fsm_compose(fsm_copy(Lbracketed),fsm_compose(fsm_complement(fsm_copy(BracketFilter)),RemoveBrackets)));
+    Leq     = fsm_compose(Lbracketed, BracketFilter);
+
+    /* Extract labels from lower side of L */
+    /* [Leq .o. [\LB:0* LB:0 \RB* RB:0]* \LB:0*].l */
+    
+    Labels = fsm_sigma_pairs_net(fsm_lower(fsm_compose(fsm_copy(Leq),fsm_concat(fsm_kleene_star(fsm_concat(fsm_kleene_star(fsm_cross_product(fsm_copy(NOLB),fsm_empty_string())),fsm_concat(fsm_cross_product(fsm_copy(LB),fsm_empty_string()),fsm_concat(fsm_kleene_star(fsm_copy(NORB)),fsm_cross_product(fsm_copy(RB),fsm_empty_string()))))),fsm_kleene_star(fsm_cross_product(fsm_copy(NOLB),fsm_empty_string()))))));
+
+    /* Cleanup = \LB* [LB:0 RB:0 \LB*]* | ~$[LB RB] */
+
+    Cleanup = fsm_minimize(fsm_union(fsm_concat(fsm_kleene_star(fsm_copy(NOLB)),fsm_kleene_star(fsm_concat(fsm_cross_product(fsm_copy(LB),fsm_empty_string()),fsm_concat(fsm_cross_product(fsm_copy(RB),fsm_empty_string()),fsm_kleene_star(fsm_copy(NOLB)))))),fsm_complement(fsm_contains(fsm_concat(fsm_copy(LB),fsm_copy(RB))))));
+
+    /* Construct the move function */
+    
+    Move = fsm_empty_string();
+
+    syms = 0;
+    for (sig = Labels->sigma; sig != NULL; sig = sig->next) {
+        /* Unclear which is faster: the first or the second version */
+        /* ThisMove = [\LB* LB:X X:LB]* \LB*       */
+        /* ThisMove = [\LB* LB:0 X 0:LB]* \LB*     */
+        if (sig->number >= 3) {
+            ThisSymbol = fsm_symbol(sig->symbol);
+            //ThisMove = fsm_concat(fsm_kleene_star(fsm_concat(fsm_kleene_star(fsm_copy(NOLB)),fsm_concat(fsm_cross_product(fsm_copy(LB),fsm_copy(ThisSymbol)),fsm_cross_product(fsm_copy(ThisSymbol),fsm_copy(LB))))), fsm_kleene_star(fsm_copy(NOLB)));
+            ThisMove = fsm_concat(fsm_kleene_star(fsm_concat(fsm_kleene_star(fsm_copy(NOLB)),fsm_concat(fsm_cross_product(fsm_copy(LB),fsm_empty_string()), fsm_concat(fsm_copy(ThisSymbol), fsm_cross_product(fsm_empty_string(),fsm_copy(LB)))))), fsm_kleene_star(fsm_copy(NOLB)));
+            
+            Move = fsm_union(Move, ThisMove);
+            syms++;
+        }
+    }
+    Move = fsm_minimize(Move);
+    if (syms == 0) {
+        //printf("no syms");
+        fsm_destroy(net);
+        return(oldnet);
+    }
+
+    /* Move until no bracket symbols remain */
+    for (;;) {
+        //printf("Zapping\n");
+        Leq = fsm_compose(Leq, fsm_copy(Cleanup));
+        if (!fsm_symbol_occurs(Leq, "@<eq<@", M_LOWER))
+            break;
+        Leq = fsm_compose(Leq, fsm_copy(Move));
+        //Leq = fsm_minimize(fsm_compose(Leq, fsm_copy(Move)));
+        //        printf("size: %i\n",Leq->statecount);
+    }
+    
+    /* Result = L .o. [Leq | Lbypass] */
+    Result = fsm_minimize(fsm_compose(net, fsm_union(fsm_lower(Leq), Lbypass)));
+    sigma_remove("@<eq<@", Result->sigma);
+    sigma_remove("@>eq>@", Result->sigma);
+    fsm_compact(Result);
+    sigma_sort(Result);
+    fsm_destroy(oldnet);
+    return(Result);
+}
+
+struct fsm *fsm_invert(struct fsm *net) {
+  struct fsm_state *fsm;
+  int i, temp;
+
+  fsm = net->states;
+  for (i = 0; (fsm+i)->state_no != -1; i++) {
+    temp = (fsm+i)->in;
+    (fsm+i)->in = (fsm+i)->out;
+    (fsm+i)->out = temp;
+  }
+  i = net->arcs_sorted_in;
+  net->arcs_sorted_in = net->arcs_sorted_out;
+  net->arcs_sorted_out = i;
+  return (net);
+}
+
+struct fsm *fsm_sequentialize(struct fsm *net) {
+  printf("Implementation pending\n");
+  return(net);
+}
+
+
+struct fsm *fsm_bimachine(struct fsm *net) {
+    printf("implementation pending\n");
+    return(net);
+}
+
+/* _leftrewr(L, a:b) does a -> b || .#. L _    */
+/* _leftrewr(?* L, a:b) does a -> b || L _     */
+/* works only with single symbols, but is fast */
+
+struct fsm *fsm_left_rewr(struct fsm *net, struct fsm *rewr) {
+    struct fsm_construct_handle *outh;
+    struct fsm_read_handle *inh;
+    struct fsm *newnet;
+    int i, maxsigma, *sigmatable, currstate, sinkstate, seensource, innum, outnum, relabelin, relabelout, addedsink;
+
+    fsm_merge_sigma(net, rewr);
+    relabelin = rewr->states->in;
+    relabelout = rewr->states->out;
+
+    inh = fsm_read_init(net);
+    sinkstate = fsm_get_num_states(inh);
+    outh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(outh, net->sigma);
+    maxsigma = sigma_max(net->sigma);
+    maxsigma++;
+    sigmatable = (int *)xxmalloc(maxsigma * sizeof(int));
+    for (i = 0; i < maxsigma; i++) {
+	*(sigmatable+i) = -1;
+    }
+    addedsink = 0;
+    while ((currstate = fsm_get_next_state(inh)) != -1) {
+	seensource = 0;
+	fsm_construct_set_final(outh, currstate);
+
+	while (fsm_get_next_state_arc(inh)) {
+	    innum = fsm_get_arc_num_in(inh);
+	    outnum = fsm_get_arc_num_out(inh);
+	    *(sigmatable+innum) = currstate;
+	    if (innum == relabelin) {
+		    seensource = 1;
+		    if (fsm_read_is_final(inh, currstate)) {
+			outnum = relabelout;
+		    }
+	    }
+	    fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), fsm_get_arc_target(inh), innum, outnum);
+	}
+	for (i = 2; i < maxsigma; i++) {
+	    if (*(sigmatable+i) != currstate && i != relabelin) {
+		fsm_construct_add_arc_nums(outh, currstate, sinkstate, i, i);
+		addedsink = 1;
+	    }
+	}
+	if (seensource == 0) {
+	    addedsink = 1;
+	    if (fsm_read_is_final(inh, currstate)) {
+		fsm_construct_add_arc_nums(outh, currstate, sinkstate, relabelin, relabelout);
+	    } else {
+		fsm_construct_add_arc_nums(outh, currstate, sinkstate, relabelin, relabelin);
+	    }
+	}
+    }
+    if (addedsink) {
+	for (i = 2; i < maxsigma; i++) {
+	    fsm_construct_add_arc_nums(outh, sinkstate, sinkstate, i, i);
+	}
+	fsm_construct_set_final(outh, sinkstate);
+    }
+    fsm_construct_set_initial(outh, 0);
+    fsm_read_done(inh);
+    newnet = fsm_construct_done(outh);
+    xxfree(sigmatable);
+    fsm_destroy(net);
+    fsm_destroy(rewr);
+    return(newnet);
+}
+
+struct fsm *fsm_add_sink(struct fsm *net, int final) {
+    struct fsm_construct_handle *outh;
+    struct fsm_read_handle *inh;
+    struct fsm *newnet;
+    int i, maxsigma, *sigmatable, currstate, sinkstate;
+
+    inh = fsm_read_init(net);
+    sinkstate = fsm_get_num_states(inh);
+    outh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(outh, net->sigma);
+    maxsigma = sigma_max(net->sigma);
+    maxsigma++;
+    sigmatable = (int *)xxmalloc(maxsigma * sizeof(int));
+    for (i = 0; i < maxsigma; i++) {
+	*(sigmatable+i) = -1;
+    }
+    while ((currstate = fsm_get_next_state(inh)) != -1) {
+	while (fsm_get_next_state_arc(inh)) {
+	    fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), fsm_get_arc_target(inh), fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+	    *(sigmatable+fsm_get_arc_num_in(inh)) = currstate;
+	}
+	for (i = 2; i < maxsigma; i++) {
+	    if (*(sigmatable+i) != currstate) {
+		fsm_construct_add_arc_nums(outh, currstate, sinkstate, i, i);
+	    }
+	}
+    }
+    for (i = 2; i < maxsigma; i++) {
+	fsm_construct_add_arc_nums(outh, sinkstate, sinkstate, i, i);
+    }
+
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(outh, i);
+    }
+    if (final == 1) {
+	fsm_construct_set_final(outh, sinkstate);
+    }
+    fsm_construct_set_initial(outh, 0);
+    fsm_read_done(inh);
+    newnet = fsm_construct_done(outh);
+    fsm_destroy(net);
+    return(newnet);
+}
+
+/* _addfinalloop(L, "#":0) adds "#":0 at all final states */
+/* _addnonfinalloop(L, "#":0) adds "#":0 at all nonfinal states */
+/* _addloop(L, "#":0) adds "#":0 at all states */
+
+/* Adds loops at finals = 0 nonfinals, finals = 1 finals, finals = 2, all */
+
+struct fsm *fsm_add_loop(struct fsm *net, struct fsm *marker, int finals) {
+    struct fsm *newnet;
+    struct fsm_construct_handle *outh;
+    struct fsm_read_handle *inh, *minh;
+    int i;
+
+    inh = fsm_read_init(net);
+    minh = fsm_read_init(marker);
+
+    outh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(outh, net->sigma);
+    
+    while (fsm_get_next_arc(inh)) {
+	fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), fsm_get_arc_target(inh), fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+    }
+    /* Where to put the loops */
+    if (finals == 1) {
+	while ((i = fsm_get_next_final(inh)) != -1) {
+	    fsm_construct_set_final(outh, i);
+	    fsm_read_reset(minh);
+	    while (fsm_get_next_arc(minh)) {
+		fsm_construct_add_arc(outh, i, i, fsm_get_arc_in(minh), fsm_get_arc_out(minh));
+	    }
+	}
+    } else if (finals == 0 || finals == 2) {
+	for (i=0; i < net->statecount; i++) {
+	    if (finals == 2 || !fsm_read_is_final(inh, i)) {
+		fsm_read_reset(minh);
+		while (fsm_get_next_arc(minh)) {
+		    fsm_construct_add_arc(outh, i, i, fsm_get_arc_in(minh), fsm_get_arc_out(minh));
+		}
+	    }
+	}
+    }
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(outh, i);
+    }
+    fsm_construct_set_initial(outh, 0);
+    fsm_read_done(inh);
+    fsm_read_done(minh);
+    newnet = fsm_construct_done(outh);
+    fsm_destroy(net);
+    return(newnet);
+}
+
+/* _marktail(?* L, 0:x) does ~$x .o. [..] -> x || L _ ;   */
+/* _marktail(?* R.r, 0:x).r does ~$x .o. [..] -> x || _ R */
+
+struct fsm *fsm_mark_fsm_tail(struct fsm *net, struct fsm *marker) {
+    struct fsm *newnet;
+    struct fsm_construct_handle *outh;
+    struct fsm_read_handle *inh, *minh;
+    int i, *mappings, maxstate, target, newtarget;
+
+    inh = fsm_read_init(net);
+    minh = fsm_read_init(marker);
+
+    outh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(outh, net->sigma);
+
+    mappings = (int *)xxcalloc(net->statecount, sizeof(int));
+    maxstate = net->statecount;
+    
+    while (fsm_get_next_arc(inh)) {
+	target = fsm_get_arc_target(inh);
+	if (fsm_read_is_final(inh, target)) {
+	    if (!*(mappings+target)) {
+		newtarget = maxstate;
+		*(mappings+target) = newtarget;
+		fsm_read_reset(minh);
+		while (fsm_get_next_arc(minh)) {
+		    fsm_construct_add_arc(outh, newtarget, target, fsm_get_arc_in(minh), fsm_get_arc_out(minh));
+		}
+		maxstate++;
+	    } else {
+		newtarget = *(mappings+target);
+	    }
+	    fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), newtarget, fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+	} else {
+	    fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), target, fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+	}
+    }
+    for (i=0; i < net->statecount; i++) {
+	fsm_construct_set_final(outh,i);
+    }
+
+    fsm_construct_set_initial(outh, 0);
+    fsm_read_done(inh);
+    fsm_read_done(minh);
+    newnet = fsm_construct_done(outh);
+    fsm_destroy(net);
+    xxfree(mappings);
+    return(newnet);
+}
+
+struct fsm *fsm_context_restrict(struct fsm *X, struct fsmcontexts *LR) {
+
+    struct fsm *Var, *Notvar, *UnionL, *UnionP, *Result, *Word;
+    struct fsmcontexts *pairs;
+
+    /* [.#. \.#.* .#.]-`[[ [\X* X C X \X*]&~[\X* [L1 X \X* X R1|...|Ln X \X* X Rn] \X*]],X,0] */
+    /* Where X = variable symbol */
+    /* The above only works if we do the subtraction iff the right hand side contains .#. in */
+    /* its alphabet */
+    /* A more generic formula is the following: */
+
+    /* `[[[(?) \.#.* (?)] - `[[[\X* X C X \X*] - [\X* [L1 X \X* X R1|...|Ln X \X* X Rn] \X*] ],X,0],.#.,0]; */
+    /* Here, the LHS is another way of saying ~[?+ .#. ?+] */
+
+    Var = fsm_symbol("@VARX@");
+    Notvar = fsm_minimize(fsm_kleene_star(fsm_term_negation(fsm_symbol("@VARX@"))));
+
+    /* We add the variable symbol to all alphabets to avoid ? mathing it */
+    /* which would cause extra nondeterminism */
+    sigma_add("@VARX@", X->sigma);
+    sigma_sort(X);
+    
+    /* Also, if any L or R is undeclared we add 0 */
+    for (pairs = LR; pairs != NULL; pairs = pairs->next) {
+        if (pairs->left == NULL) {
+            pairs->left = fsm_empty_string();
+        } else {
+            sigma_add("@VARX@",pairs->left->sigma);
+	    sigma_substitute(".#.", "@#@", pairs->left->sigma);
+            sigma_sort(pairs->left);
+        }
+        if (pairs->right == NULL) {
+            pairs->right = fsm_empty_string();
+        } else {
+            sigma_add("@VARX@",pairs->right->sigma);
+	    sigma_substitute(".#.", "@#@", pairs->right->sigma);
+            sigma_sort(pairs->right);
+        }
+    }
+
+    UnionP = fsm_empty_set();
+    
+    for (pairs = LR; pairs != NULL ; pairs = pairs->next) {
+        UnionP = fsm_minimize(fsm_union(fsm_minimize(fsm_concat(fsm_copy(pairs->left),fsm_concat(fsm_copy(Var),fsm_concat(fsm_copy(Notvar),fsm_concat(fsm_copy(Var),fsm_copy(pairs->right)))))), UnionP));
+    }
+    
+    UnionL = fsm_minimize(fsm_concat(fsm_copy(Notvar),fsm_concat(fsm_copy(Var), fsm_concat(fsm_copy(X), fsm_concat(fsm_copy(Var),fsm_copy(Notvar))))));
+
+    Result = fsm_intersect(UnionL, fsm_complement(fsm_concat(fsm_copy(Notvar),fsm_minimize(fsm_concat(fsm_copy(UnionP),fsm_copy(Notvar))))));
+    if (sigma_find("@VARX@", Result->sigma) != -1) {
+        Result = fsm_complement(fsm_substitute_symbol(Result, "@VARX@","@_EPSILON_SYMBOL_@"));
+    } else {
+	Result = fsm_complement(Result);
+    }
+
+    if (sigma_find("@#@", Result->sigma) != -1) {
+	Word = fsm_minimize(fsm_concat(fsm_symbol("@#@"),fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol("@#@"))),fsm_symbol("@#@"))));
+        Result = fsm_intersect(Word, Result);
+        Result = fsm_substitute_symbol(Result, "@#@", "@_EPSILON_SYMBOL_@");
+    }
+    fsm_destroy(UnionP);
+    fsm_destroy(Var);
+    fsm_destroy(Notvar);
+    fsm_destroy(X);
+    fsm_clear_contexts(pairs);
+    return(Result);
+}
+
+struct fsm *fsm_flatten(struct fsm *net, struct fsm *epsilon) {
+    struct fsm *newnet;
+    struct fsm_construct_handle *outh;
+    struct fsm_read_handle *inh, *eps;
+    int i, maxstate, in, out, target;
+    char *epssym, *instring, *outstring;
+
+    net = fsm_minimize(net);
+    
+    inh = fsm_read_init(net);
+    eps = fsm_read_init(epsilon);
+    if (fsm_get_next_arc(eps) == -1) {
+	fsm_destroy(net);
+	fsm_destroy(epsilon);
+	return NULL;
+    }
+    epssym = xxstrdup(fsm_get_arc_in(eps));
+    fsm_read_done(eps);
+
+    outh = fsm_construct_init(net->name);
+    maxstate = net->statecount;
+
+    fsm_construct_copy_sigma(outh, net->sigma);
+
+    while (fsm_get_next_arc(inh)) {
+	target = fsm_get_arc_target(inh);
+	in = fsm_get_arc_num_in(inh);
+	out = fsm_get_arc_num_out(inh);
+	if (in == EPSILON || out == EPSILON)  {
+	    instring = fsm_get_arc_in(inh);
+	    outstring = fsm_get_arc_out(inh);
+	    if (in == EPSILON)  { instring = epssym; }
+	    if (out == EPSILON) { outstring = epssym; }
+
+	    fsm_construct_add_arc(outh, fsm_get_arc_source(inh), maxstate, instring, instring);
+	    fsm_construct_add_arc(outh, maxstate, target, outstring, outstring);
+	} else {
+	    fsm_construct_add_arc_nums(outh, fsm_get_arc_source(inh), maxstate, in, in);
+	    fsm_construct_add_arc_nums(outh, maxstate, target, out, out);
+	}
+	maxstate++;
+    }
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(outh, i);
+    }
+    while ((i = fsm_get_next_initial(inh)) != -1) {
+	fsm_construct_set_initial(outh, i);
+    }
+
+    fsm_read_done(inh);
+    newnet = fsm_construct_done(outh);
+    fsm_destroy(net);
+    fsm_destroy(epsilon);
+    xxfree(epssym);
+    return(newnet);
+}
+
+/* Removes IDENTITY and UNKNOWN transitions. If mode = 1, only removes UNKNOWNs */
+struct fsm *fsm_close_sigma(struct fsm *net, int mode) {
+    struct fsm *newnet;
+    struct fsm_construct_handle *newh;
+    struct fsm_read_handle *inh;
+    int i;
+
+    inh = fsm_read_init(net);
+    newh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(newh, net->sigma);
+
+    while (fsm_get_next_arc(inh)) {
+	if ((fsm_get_arc_num_in(inh) != UNKNOWN && fsm_get_arc_num_in(inh) != IDENTITY && fsm_get_arc_num_out(inh) != UNKNOWN && fsm_get_arc_num_out(inh) != IDENTITY) || (mode == 1 && fsm_get_arc_num_in(inh) != UNKNOWN && fsm_get_arc_num_out(inh) != UNKNOWN))
+	    fsm_construct_add_arc_nums(newh, fsm_get_arc_source(inh), fsm_get_arc_target(inh), fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+    }
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_set_final(newh, i);
+    }
+    while ((i = fsm_get_next_initial(inh)) != -1) {
+	fsm_construct_set_initial(newh, i);
+    }
+    fsm_read_done(inh);
+    newnet = fsm_construct_done(newh);
+    fsm_destroy(net);
+    return(fsm_minimize(newnet));
+}
diff --git a/back-ends/foma/cpp-version/define.cc b/back-ends/foma/cpp-version/define.cc
new file mode 100644
index 0000000..63b9d4d
--- /dev/null
+++ b/back-ends/foma/cpp-version/define.cc
@@ -0,0 +1,147 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "foma.h"
+
+/* Find a defined symbol from the symbol table */
+/* Return the corresponding FSM                */
+struct fsm *find_defined(struct defined_networks *def, char *string) {
+    struct defined_networks *d;
+    for (d = def; d != NULL; d = d->next) {
+	if (d->name != NULL && strcmp(string, d->name) == 0) {
+	    return(d->net);
+	}
+    }
+    return NULL;
+}
+
+struct defined_networks *defined_networks_init(void) {
+    struct defined_networks *def;
+    def = (struct defined_networks*)calloc(1, sizeof(struct defined_networks)); /* Dummy first entry, so we can maintain the ptr */
+    return def;
+}
+
+struct defined_functions *defined_functions_init(void) {
+    struct defined_functions *deff;
+    deff = (struct defined_functions*)calloc(1, sizeof(struct defined_functions)); /* Dummy first entry */
+    return deff;
+}
+
+/* Removes a defined network from the list                 */
+/* Returns 0 on success, 1 if the definition did not exist */
+/* Undefines all if NULL is passed as the string argument  */
+
+int remove_defined(struct defined_networks *def, char *string) {
+    struct defined_networks *d, *d_prev, *d_next;
+    int exists = 0;
+    /* Undefine all */
+    if (string == NULL) {
+      for (d = def; d != NULL; d = d_next) {
+        d_next = d->next;
+        if (d->net != NULL)
+          fsm_destroy(d->net);
+        if (d->name != NULL)
+          xxfree(d->name);
+      }
+      return 0;
+    }
+    d_prev = NULL;
+    for (d = def; d != NULL; d_prev = d, d = d->next) {
+	if (d->name != NULL && strcmp(d->name, string) == 0) {
+	    exists = 1;
+	    break;
+	}
+    }
+    if (exists == 0) {
+	return 1;
+    }
+    if (d == def) {
+	if (d->next != NULL) {
+	    fsm_destroy(d->net);
+	    xxfree(d->name);
+	    d->name = d->next->name;
+	    d->net = d->next->net;
+	    d_next = d->next->next;
+	    xxfree(d->next);
+	    d->next = d_next;
+	} else {
+	    fsm_destroy(d->net);
+	    xxfree(d->name);
+            d->next = NULL;
+            d->name = NULL;
+            d->net = NULL;
+	}
+    } else {
+	fsm_destroy(d->net);
+	xxfree(d->name);
+	d_prev->next = d->next;
+	xxfree(d);
+    }
+    return 0;
+}
+
+/* Finds defined regex "function" based on name, numargs */
+/* Returns the corresponding regex                       */
+char *find_defined_function(struct defined_functions *deff, char *name, int numargs) {
+    struct defined_functions *d;
+    for (d = deff ; d != NULL; d = d->next) {
+        if (d->name != NULL && strcmp(d->name, name) == 0 && d->numargs == numargs) {
+            return(d->regex);
+        }
+    }
+    return NULL;
+}
+
+/* Add a function to list of defined functions */
+int add_defined_function(struct defined_functions *deff, char *name, char *regex, int numargs) {
+    struct defined_functions *d;
+    for (d = deff; d != NULL; d = d->next) {
+	if (d->name != NULL && strcmp(d->name, name) == 0 && d->numargs == numargs) {
+	    xxfree(d->regex);
+	    d->regex = xxstrdup(regex);
+	    printf("redefined %s@%i)\n", name, numargs);
+	    return 1;
+	}
+    }
+    if (deff->name == NULL) {
+	d = deff;
+    } else {
+        d = (struct defined_functions*)xxmalloc(sizeof(struct defined_functions));
+	d->next = deff->next;
+	deff->next = d;
+    }
+    d->name = xxstrdup(name);
+    d->regex = xxstrdup(regex);
+    d->numargs = numargs;
+    return 0;
+}
+
+/* Add a network to list of defined networks */
+/* Returns 0 on success or 1 on redefinition */
+/* Always maintain head of list at same ptr */
+
+int add_defined(struct defined_networks *def, struct fsm *net, char *string) {
+    struct defined_networks *d;
+    if (net == NULL)
+	return 0;
+    fsm_count(net);
+    for (d = def; d != NULL; d = d->next) {
+	if (d->name != NULL && strcmp(d->name, string) == 0) {
+	    xxfree(d->net);
+	    xxfree(d->name);
+	    d->net = net;
+	    d->name = xxstrdup(string);
+	    return 1;
+	}
+    }
+    if (def->name == NULL) {
+	d = def;
+    } else {
+        d = (struct defined_networks*)xxmalloc(sizeof(struct defined_networks));
+	d->next = def->next;
+	def->next = d;
+    }
+    d->name = xxstrdup(string);
+    d->net = net;
+    return 0;
+}
diff --git a/back-ends/foma/cpp-version/determinize.cc b/back-ends/foma/cpp-version/determinize.cc
new file mode 100644
index 0000000..89f7a22
--- /dev/null
+++ b/back-ends/foma/cpp-version/determinize.cc
@@ -0,0 +1,885 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include "foma.h"
+
+#define SUBSET_EPSILON_REMOVE 1
+#define SUBSET_DETERMINIZE 2
+#define SUBSET_TEST_STAR_FREE 3
+
+#define NHASH_LOAD_LIMIT 2 /* load limit for nhash table size */
+
+static int fsm_linecount, num_states, num_symbols, epsilon_symbol, *single_sigma_array, *double_sigma_array, limit, num_start_states, op;
+
+static Boolean *finals, deterministic, numss;
+
+struct e_closure_memo {
+    int state;
+    int mark;
+    struct e_closure_memo *target;
+    struct e_closure_memo *next;
+};
+
+static unsigned int primes[26] = {61,127,251,509,1021,2039,4093,8191,16381,32749,65521,131071,262139,524287,1048573,2097143,4194301,8388593,16777213,33554393,67108859,134217689,268435399,536870909,1073741789,2147483647};
+
+static struct e_closure_memo *e_closure_memo;
+
+int T_last_unmarked, T_limit;
+
+struct nhash_list {
+    int setnum;
+    unsigned int size;
+    unsigned int set_offset;
+    struct nhash_list *next;
+};
+
+struct T_memo {
+    unsigned char finalstart;
+    unsigned int size;
+    unsigned int set_offset;
+};
+
+// HFST MODIFICATIONS: struct trans_list -> struct trans_list_struct
+//                     struct trans_array -> struct trans_list_array
+// because some compilers complain about struct and variable having the same name
+
+static struct trans_list_struct {
+    int inout;
+    int target;
+} *trans_list;
+
+static struct trans_array_struct {
+    struct trans_list_struct *transitions;
+    unsigned int size;
+    unsigned int tail;
+} *trans_array;
+
+static struct T_memo *T_ptr;
+
+static int nhash_tablesize, nhash_load, current_setnum, *e_table, *marktable, *temp_move, mainloop, maxsigma, *set_table, set_table_size, star_free_mark;
+static unsigned int set_table_offset;
+static struct nhash_list *table;
+
+extern int add_fsm_arc(struct fsm_state *fsm, int offset, int state_no, int in, int out, int target, int final_state, int start_state);
+
+static void init(struct fsm *net);
+INLINE static int e_closure(int states);
+INLINE static int set_lookup(int *lookup_table, int size);
+static int initial_e_closure(struct fsm *network);
+static void memoize_e_closure(struct fsm_state *fsm);
+static int next_unmarked(void);
+static void single_symbol_to_symbol_pair(int symbol, int *symbol_in, int *symbol_out);
+static int symbol_pair_to_single_symbol(int in, int out);
+static void sigma_to_pairs(struct fsm *net);
+static int nhash_find_insert(int *set, int setsize);
+INLINE static int hashf(int *set, int setsize);
+static int nhash_insert(int hashval, int *set, int setsize);
+static void nhash_rebuild_table ();
+static void nhash_init (int initial_size);
+static void nhash_free(struct nhash_list *nptr, int size);
+static void e_closure_free();
+static void init_trans_array(struct fsm *net);
+static struct fsm *fsm_subset(struct fsm *net, int operation);
+
+struct fsm *fsm_epsilon_remove(struct fsm *net) {
+    return(fsm_subset(net, SUBSET_EPSILON_REMOVE));
+}
+
+struct fsm *fsm_determinize(struct fsm *net) {
+    return(fsm_subset(net, SUBSET_DETERMINIZE));
+}
+
+int fsm_isstarfree(struct fsm *net) {
+    #define DFS_WHITE 0
+    #define DFS_GRAY 1
+    #define DFS_BLACK 2
+
+    struct fsm *sfnet;
+    struct state_array *state_array;
+    struct fsm_state *curr_ptr;
+    int v, vp, is_star_free;
+    short int in;
+    char *dfs_map;
+
+    sfnet = fsm_subset(net, SUBSET_TEST_STAR_FREE);
+    is_star_free = 1;
+
+    state_array = map_firstlines(net);
+    ptr_stack_clear();
+    ptr_stack_push(state_array->transitions);
+
+    dfs_map = (char*)xxcalloc(sfnet->statecount, sizeof(char));
+    while(!ptr_stack_isempty()) {
+
+        curr_ptr = (fsm_state*)ptr_stack_pop();
+    nopop:
+        v = curr_ptr->state_no; /* source state number */
+        vp = curr_ptr->target;  /* target state number */
+
+        if (v == -1 || vp == -1) {
+            *(dfs_map+v) = DFS_BLACK;
+            continue;
+        }
+        *(dfs_map+v) = DFS_GRAY;
+
+        in = curr_ptr->in;
+        if (*(dfs_map+vp) == DFS_GRAY && in == maxsigma) {
+            /* Not star-free */
+            is_star_free = 0;
+            break;
+        }
+        if (v == (curr_ptr+1)->state_no) {
+            ptr_stack_push(curr_ptr+1);
+        }
+        if (*(dfs_map+vp) == DFS_WHITE) {
+            curr_ptr = (state_array+vp)->transitions;
+            goto nopop;
+        }
+    }
+    ptr_stack_clear();
+    xxfree(dfs_map);
+    xxfree(state_array);
+    //stack_add(sfnet);
+    return(is_star_free);
+}
+
+static struct fsm *fsm_subset(struct fsm *net, int operation) {
+
+    int T, U;
+    
+    if (net->is_deterministic == YES && operation != SUBSET_TEST_STAR_FREE) {
+        return(net);
+    }
+    /* Export this var */
+    op = operation;
+    fsm_count(net);
+    num_states = net->statecount;
+    deterministic = 1;
+    init(net);
+    nhash_init((num_states < 12) ? 6 : num_states/2);
+    
+    T = initial_e_closure(net);
+
+    int_stack_clear();
+    
+    if (deterministic == 1 && epsilon_symbol == -1 && num_start_states == 1 && numss == 0) {
+        net->is_deterministic = YES;
+        net->is_epsilon_free = YES;
+        nhash_free(table, nhash_tablesize);
+        xxfree(T_ptr);
+        xxfree(e_table);
+        xxfree(trans_list);
+        xxfree(trans_array);
+        xxfree(double_sigma_array);
+        xxfree(single_sigma_array);
+        xxfree(finals);
+        xxfree(temp_move);
+        xxfree(set_table);
+        return(net);
+    }
+
+    if (operation == SUBSET_EPSILON_REMOVE && epsilon_symbol == -1) {
+        net->is_epsilon_free = YES;
+        nhash_free(table, nhash_tablesize);
+        xxfree(T_ptr);
+        xxfree(e_table);
+        xxfree(trans_list);
+        xxfree(trans_array);
+        xxfree(double_sigma_array);
+        xxfree(single_sigma_array);
+        xxfree(finals);
+        xxfree(temp_move);
+        xxfree(set_table);
+        return(net);
+    }
+
+    if (operation == SUBSET_TEST_STAR_FREE) {
+        fsm_state_init(sigma_max(net->sigma)+1);
+        star_free_mark = 0;
+    } else {
+        fsm_state_init(sigma_max(net->sigma));
+        xxfree(net->states);
+    }
+
+    /* init */
+
+    do {
+        int i, j, tail, setsize, *theset, stateno, has_trans, minsym, next_minsym, trgt, symbol_in, symbol_out;
+        struct trans_list_struct *transitions;
+        struct trans_array_struct *tptr;
+
+        fsm_state_set_current_state(T, (T_ptr+T)->finalstart, T == 0 ? 1 : 0);
+        
+        /* Prepare set */
+        setsize = (T_ptr+T)->size;
+        theset = set_table+(T_ptr+T)->set_offset;
+        minsym = INT_MAX;
+        has_trans = 0;
+        for (i = 0; i < setsize; i++) {
+            stateno = *(theset+i);
+            tptr = trans_array+stateno;
+            tptr->tail = 0;
+            if (tptr->size == 0)
+                continue;
+            if ((tptr->transitions)->inout < minsym) {
+                minsym = (tptr->transitions)->inout;
+                has_trans = 1;
+            }
+        }
+        if (!has_trans) {
+            /* close state */
+            fsm_state_end_state();
+            continue;
+        }
+        
+        /* While set not empty */
+
+        for (next_minsym = INT_MAX; minsym != INT_MAX ; minsym = next_minsym, next_minsym = INT_MAX) {
+            theset = set_table+(T_ptr+T)->set_offset;
+            
+            for (i = 0, j = 0 ; i < setsize; i++) {
+                
+                stateno = *(theset+i);
+                tptr = trans_array+stateno;
+                tail = tptr->tail;
+                transitions = (tptr->transitions)+tail;
+                
+                while (tail < tptr->size &&  transitions->inout == minsym) {
+                    trgt = transitions->target;
+                    if (*(e_table+(trgt)) != mainloop) {
+                        *(e_table+(trgt)) = mainloop;
+                        *(temp_move+j) = trgt;
+                        j++;
+                        
+                        if (operation == SUBSET_EPSILON_REMOVE) {
+                            mainloop++;
+                            if ((U = e_closure(j)) != -1) {
+                                single_symbol_to_symbol_pair(minsym, &symbol_in, &symbol_out);
+                                fsm_state_add_arc(T, symbol_in, symbol_out, U, (T_ptr+T)->finalstart, T == 0 ? 1 : 0);
+                                j = 0;
+                            }
+                        }
+                    }
+                    tail++;
+                    transitions++;
+                }
+                
+                tptr->tail = tail;
+                
+                if (tail == tptr->size)
+                    continue;
+                /* Check next minsym */
+                if (transitions->inout < next_minsym) {
+                    next_minsym = transitions->inout;
+                }
+            }
+            if (operation == SUBSET_DETERMINIZE) {
+                mainloop++;
+                if ((U = e_closure(j)) != -1) {
+                    single_symbol_to_symbol_pair(minsym, &symbol_in, &symbol_out);
+                    fsm_state_add_arc(T, symbol_in, symbol_out, U, (T_ptr+T)->finalstart, T == 0 ? 1 : 0);
+                }
+            }
+            if (operation == SUBSET_TEST_STAR_FREE) {
+                mainloop++;
+                if ((U = e_closure(j)) != -1) {
+                    single_symbol_to_symbol_pair(minsym, &symbol_in, &symbol_out);
+                    fsm_state_add_arc(T, symbol_in, symbol_out, U, (T_ptr+T)->finalstart, T == 0 ? 1 : 0);
+                    if (star_free_mark == 1) {
+                        //fsm_state_add_arc(T, maxsigma, maxsigma, U, (T_ptr+T)->finalstart, T == 0 ? 1 : 0);
+                        star_free_mark = 0;
+                    }
+                }
+            }
+        }
+        /* end state */
+        fsm_state_end_state();
+    } while ((T = next_unmarked()) != -1);
+    
+    /* wrapup() */
+    nhash_free(table, nhash_tablesize);
+    xxfree(set_table);
+    xxfree(T_ptr);
+    xxfree(temp_move);
+    xxfree(e_table);
+    xxfree(trans_list);
+    xxfree(trans_array);
+    
+    if (epsilon_symbol != -1)
+        e_closure_free();
+    xxfree(double_sigma_array);
+    xxfree(single_sigma_array);
+    xxfree(finals);
+    fsm_state_close(net);
+    return(net);
+}
+
+static void init(struct fsm *net) {
+    /* A temporary table for handling epsilon closure */
+    /* to avoid doubles */
+
+    e_table = (int*)xxcalloc(net->statecount,sizeof(int));
+
+    /* Counter for our access tables */
+
+    mainloop = 1;
+
+    /* Temporary table for storing sets and */
+    /* passing to hash function */
+    
+    /* Table for listing current results of move & e-closure */
+    temp_move = (int*)xxmalloc((net->statecount + 1) *sizeof(int));
+    
+    /* We malloc this much memory to begin with for the new fsm */
+    /* Then grow it by the double as needed */
+
+    limit = next_power_of_two(net->linecount);
+    fsm_linecount = 0;
+    sigma_to_pairs(net);
+
+    /* Optimistically malloc T_ptr array */
+    /* We allocate memory for a number of pointers to a set of states */
+    /* To handle fast lookup in array */
+    /* Optimistically, we choose the initial size to be the number of */
+    /* states in the non-deterministic fsm */
+    
+    T_last_unmarked = 0;
+    T_limit = next_power_of_two(num_states);
+
+    T_ptr = (struct T_memo*)xxcalloc(T_limit,sizeof(struct T_memo));
+
+    /* Stores all sets consecutively in one table */
+    /* T_ptr->set_offset and size                 */
+    /* are used to retrieve the set               */
+
+    set_table_size = next_power_of_two(num_states);
+    set_table = (int*)xxmalloc(set_table_size*sizeof(int));
+    set_table_offset = 0;
+
+    init_trans_array(net);
+}
+
+static int trans_sort_cmp(const void *a, const void *b) {
+  return (((const struct trans_list_struct *)a)->inout - ((const struct trans_list_struct *)b)->inout);
+}
+
+static void init_trans_array(struct fsm *net) {
+    struct trans_list_struct *arrptr;
+    struct fsm_state *fsm;
+    int i, j, laststate, lastsym, inout, size, state;
+
+    arrptr = trans_list = (struct trans_list_struct*)xxmalloc(net->linecount * sizeof(struct trans_list_struct));
+    trans_array = (struct trans_array_struct*)xxcalloc(net->statecount, sizeof(struct trans_array_struct));
+    
+    laststate = -1;
+    fsm = net->states;
+
+    for (i=0, size = 0; (fsm+i)->state_no != -1; i++) {
+        state = (fsm+i)->state_no;
+        if (state != laststate) {
+            if (laststate != -1) {
+                (trans_array+laststate)->size = size;
+            }
+            (trans_array+state)->transitions = arrptr;
+            size = 0;
+        }
+        laststate = state;
+
+        if ((fsm+i)->target == -1)
+            continue;
+        inout = symbol_pair_to_single_symbol((fsm+i)->in, (fsm+i)->out);
+        if (inout == epsilon_symbol)
+            continue;
+        
+        arrptr->inout = inout;
+        arrptr->target = (fsm+i)->target;
+        arrptr++;
+        size++;
+    }
+
+    if (laststate != -1) {
+        (trans_array+laststate)->size = size;
+    }
+
+    for (i=0; i < net->statecount; i++) {
+        arrptr = (trans_array+i)->transitions;
+        size = (trans_array+i)->size;
+        if (size > 1) {
+            qsort(arrptr, size, sizeof(struct trans_list_struct), trans_sort_cmp);
+            lastsym = -1;
+            /* Figure out if we're already deterministic */
+            for (j=0; j < size; j++) {
+                if ((arrptr+j)->inout == lastsym)
+                    deterministic = 0;
+                lastsym = (arrptr+j)->inout;
+            }
+        }
+    }
+}
+
+INLINE static int e_closure(int states) {
+
+    int i, set_size;
+    struct e_closure_memo *ptr;
+
+    /* e_closure extends the list of states which are reachable */
+    /* and appends these to e_table                             */
+
+    if (epsilon_symbol == -1)
+        return(set_lookup(temp_move, states));
+
+    if (states == 0)
+        return -1;
+
+    mainloop--;
+    
+    set_size = states;
+
+    for (i = 0; i < states; i++) {
+
+        /* State number we want to do e-closure on */
+        ptr = e_closure_memo + *(temp_move+i);
+        if (ptr->target == NULL)
+            continue;
+        ptr_stack_push(ptr);
+
+        while (!(ptr_stack_isempty())) {
+	    ptr = (struct e_closure_memo*)ptr_stack_pop();
+            /* Don't follow if already seen */
+            if (*(marktable+ptr->state) == mainloop)
+                continue;
+            
+            ptr->mark = mainloop;
+            *(marktable+ptr->state) = mainloop;
+            /* Add to tail of list */
+            if (*(e_table+(ptr->state)) != mainloop) {
+                *(temp_move+set_size) = ptr->state;
+                *(e_table+(ptr->state)) = mainloop;
+                set_size++;
+            }
+            
+            if (ptr->target == NULL)
+                continue;
+            /* Traverse chain */
+
+            for (; ptr != NULL ; ptr = ptr->next) {
+                if (ptr->target->mark != mainloop) {
+                    /* Push */
+                    ptr->target->mark = mainloop;
+                    ptr_stack_push(ptr->target);
+                }
+            }
+        }
+    }
+
+    mainloop++;
+    return(set_lookup(temp_move, set_size));
+}
+
+INLINE static int set_lookup (int *lookup_table, int size) {
+
+  /* Look up a set and its corresponding state number */
+  /* if it doesn't exist from before, assign a state number */
+  
+    return(nhash_find_insert(lookup_table, size));
+  
+}
+
+void add_T_ptr(int setnum, int setsize, unsigned int theset, int fs) {
+
+  int i;
+  if (setnum >= T_limit) {
+    T_limit *= 2;
+    T_ptr = (struct T_memo*)xxrealloc(T_ptr, sizeof(struct T_memo)*T_limit);
+    for (i=setnum; i < T_limit; i++) {
+        (T_ptr+i)->size = 0;
+    }
+  }
+  
+  (T_ptr + setnum)->size = setsize;
+  (T_ptr + setnum)->set_offset = theset;
+  (T_ptr + setnum)->finalstart = fs;
+  int_stack_push(setnum);
+
+}
+
+static int initial_e_closure(struct fsm *net) {
+
+    struct fsm_state *fsm;
+    int i,j;
+
+    finals = (Boolean*)xxcalloc(num_states, sizeof(Boolean));
+
+    num_start_states = 0;
+    fsm = net->states;
+    
+    /* Create lookups for each state */
+    for (i=0,j=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->final_state) {
+            finals[(fsm+i)->state_no] = 1;
+        }
+        /* Add the start states as the initial set */
+        if ((op == SUBSET_TEST_STAR_FREE) || ((fsm+i)->start_state)) {
+            if (*(e_table+((fsm+i)->state_no)) != mainloop) {
+                num_start_states++;
+                numss = (fsm+i)->state_no;
+                *(e_table+((fsm+i)->state_no)) = mainloop;
+                *(temp_move+j) = (fsm+i)->state_no;
+                j++;
+            }
+        }
+    }
+    mainloop++;
+    /* Memoize e-closure(u) */
+    if (epsilon_symbol != -1) {
+        memoize_e_closure(fsm);
+    }
+    return(e_closure(j));
+}
+ 
+static void memoize_e_closure(struct fsm_state *fsm) {
+    
+    int i, state, laststate, *redcheck;
+    struct e_closure_memo *ptr;
+    
+    e_closure_memo = (struct e_closure_memo*)xxcalloc(num_states,sizeof(struct e_closure_memo));
+    marktable = (int*)xxcalloc(num_states,sizeof(int));
+    /* Table for avoiding redundant epsilon arcs in closure */
+    redcheck = (int*)xxmalloc(num_states*sizeof(int));
+
+    for (i=0; i < num_states; i++) {
+        ptr = e_closure_memo+i;
+        ptr->state = i;
+        ptr->target = NULL;
+        *(redcheck+i) = -1;
+    }
+
+    laststate = -1;
+
+    for (i=0; ;i++) {
+        
+        state = (fsm+i)->state_no;
+        
+        if (state != laststate) {
+            if (!int_stack_isempty()) {
+                deterministic = 0;
+                ptr = e_closure_memo+laststate;
+                ptr->target = e_closure_memo+int_stack_pop();
+                while (!int_stack_isempty()) {
+		    ptr->next = (struct e_closure_memo*)xxmalloc(sizeof(struct e_closure_memo));
+                    ptr->next->state = laststate;
+                    ptr->next->target = e_closure_memo+int_stack_pop();
+                    ptr->next->next = NULL;
+                    ptr = ptr->next;
+                }
+            }
+        }
+        if (state == -1) {
+            break;
+        }
+        if ((fsm+i)->target == -1) {
+            continue;
+        }
+        /* Check if we have a redundant epsilon arc */
+        if ((fsm+i)->in == EPSILON && (fsm+i)->out == EPSILON) {
+            if (*(redcheck+((fsm+i)->target)) != (fsm+i)->state_no) {
+                if ((fsm+i)->target != (fsm+i)->state_no) {
+                    int_stack_push((fsm+i)->target);
+                    *(redcheck+((fsm+i)->target)) = (fsm+i)->state_no;
+                }
+            }
+            laststate = state;
+        }
+    }
+    xxfree(redcheck);
+}
+ 
+static int next_unmarked(void) {
+    if ((int_stack_isempty()))
+        return -1;
+    return(int_stack_pop());
+
+    if ((T_limit <= T_last_unmarked + 1) || (T_ptr+T_last_unmarked+1)->size == 0) {
+        return -1;
+    } else {
+        T_last_unmarked++;
+        return(T_last_unmarked);
+    }
+}
+
+static void single_symbol_to_symbol_pair(int symbol, int *symbol_in, int *symbol_out) {
+
+  *symbol_in = *(single_sigma_array+(symbol*2));
+  *symbol_out = *(single_sigma_array+(symbol*2+1));
+  
+}
+
+static int symbol_pair_to_single_symbol(int in, int out) {
+  return(*(double_sigma_array+maxsigma*in+out));
+}
+
+static void sigma_to_pairs(struct fsm *net) {
+  
+  int i, j, x, y, z, next_x = 0;
+  struct fsm_state *fsm;
+
+  fsm = net->states;
+
+  epsilon_symbol = -1;
+  maxsigma = sigma_max(net->sigma);
+  maxsigma++;
+
+  single_sigma_array = (int*)xxmalloc(2*maxsigma*maxsigma*sizeof(int));
+  double_sigma_array = (int*)xxmalloc(maxsigma*maxsigma*sizeof(int));
+  
+  for (i=0; i < maxsigma; i++) {
+    for (j=0; j< maxsigma; j++) {
+      *(double_sigma_array+maxsigma*i+j) = -1;
+    }
+  }
+  
+  /* f(x) -> y,z sigma pair */
+  /* f(y,z) -> x simple entry */
+  /* if exists f(n) <-> EPSILON, EPSILON, save n */
+  /* symbol(x) x>=1 */
+
+  /* Forward mapping: */
+  /* *(double_sigma_array+maxsigma*in+out) */
+
+  /* Backmapping: */
+  /* *(single_sigma_array+(symbol*2) = in(symbol) */
+  /* *(single_sigma_array+(symbol*2+1) = out(symbol) */
+
+  /* Table for checking whether a state is final */
+
+  x = 0;
+  net->arity = 1;
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    y = (fsm+i)->in;
+    z = (fsm+i)->out;
+    if ((y == -1) || (z == -1))
+      continue;
+    if (y != z || y == UNKNOWN || z == UNKNOWN)
+        net->arity = 2;
+    if (*(double_sigma_array+maxsigma*y+z) == -1) {
+      *(double_sigma_array+maxsigma*y+z) = x;
+      *(single_sigma_array+next_x) = y;
+      next_x++;
+      *(single_sigma_array+next_x) = z;
+      next_x++;
+      if (y == EPSILON && z == EPSILON) {
+	epsilon_symbol = x;
+      }
+      x++;
+    }
+  }
+  num_symbols = x;
+}
+
+
+/* Functions for hashing n integers */
+/* with permutations hashing to the same value */
+/* necessary for subset construction */
+
+static int nhash_find_insert(int *set, int setsize) {
+    int j, found, *currlist;
+    struct nhash_list *tableptr;
+    unsigned int hashval;
+    
+    hashval = hashf(set, setsize);
+    if ((table+hashval)->size == 0) {
+        return(nhash_insert(hashval, set, setsize));
+    } else {
+        for (tableptr=(table+hashval); tableptr != NULL; tableptr = tableptr->next) {
+            if ((tableptr)->size != setsize) {
+                continue;
+            } else {
+                /* Compare the list at hashval position */
+                /* to the current set by looking at etable */
+                /* entries */
+                for (j=0, found = 1, currlist= set_table+tableptr->set_offset; j < setsize; j++) {
+                    if (*(e_table+(*(currlist+j))) != (mainloop-1)) {
+                        found = 0;
+                        break;
+                    }
+                }
+                if (op == SUBSET_TEST_STAR_FREE && found == 1) {
+                    for (j=0, currlist= set_table+tableptr->set_offset; j < setsize; j++) {
+                        if (*(set+j) != *(currlist+j)) {
+                            /* Set mark */
+                            star_free_mark = 1;
+                        }
+                    }
+                }
+                if (found == 1) {
+                    return(tableptr->setnum);
+                }
+            }
+        }
+        
+        if (nhash_load / NHASH_LOAD_LIMIT > nhash_tablesize) {
+            nhash_rebuild_table();
+            hashval = hashf(set, setsize);
+        }
+        return(nhash_insert(hashval, set, setsize));
+    }
+}
+
+INLINE static int hashf(int *set, int setsize) {
+  int i;
+  unsigned int hashval, sum = 0;
+  hashval = 6703271;
+  for (i = 0; i < setsize; i++) {
+      hashval = (unsigned int) (*(set+i) + 1103 * setsize) * hashval;
+      sum += *(set+i) + i;
+  }
+  hashval = hashval + sum * 31;
+  hashval = (hashval % nhash_tablesize);
+  return hashval;
+}
+
+static unsigned int move_set(int *set, int setsize) {
+    unsigned int old_offset;
+    if (set_table_offset + setsize >= set_table_size) {
+        while (set_table_offset + setsize >= set_table_size) {
+            set_table_size *= 2;
+        }
+        set_table = (int*)xxrealloc(set_table, set_table_size * sizeof(int));
+    }
+    memcpy(set_table+set_table_offset, set, setsize * sizeof(int));
+    old_offset = set_table_offset;
+    set_table_offset += setsize;
+    return(old_offset);
+}
+
+static int nhash_insert(int hashval, int *set, int setsize) {
+  struct nhash_list *tableptr;
+  int i, fs = 0;
+
+  current_setnum++;
+  tableptr = table+hashval;
+
+  nhash_load++;
+  for (i = 0; i < setsize; i++) {
+      if (finals[*(set+i)])
+          fs = 1;
+  }
+  if (tableptr->size == 0) {
+    
+      tableptr->set_offset = move_set(set, setsize);
+      tableptr->size = setsize;
+      tableptr->setnum = current_setnum;
+      
+      add_T_ptr(current_setnum, setsize, tableptr->set_offset, fs);
+      return(current_setnum);
+  }
+  
+  tableptr = (struct nhash_list*)xxmalloc(sizeof(struct nhash_list));
+  tableptr->next = (table+hashval)->next;
+  (table+hashval)->next = tableptr;
+  tableptr->setnum = current_setnum;
+  tableptr->size = setsize;
+  tableptr->set_offset = move_set(set, setsize);
+  
+  add_T_ptr(current_setnum, setsize, tableptr->set_offset, fs);
+  return(current_setnum);
+}
+
+static void nhash_rebuild_table () {
+    int i, oldsize;
+    struct nhash_list *oldtable, *tableptr, *ntableptr, *newptr;
+    unsigned int hashval;
+    
+    oldtable = table;
+    oldsize = nhash_tablesize;
+
+    nhash_load = 0;
+    for (i=0; primes[i] < nhash_tablesize; i++) { }
+    nhash_tablesize = primes[(i+1)];
+    
+    table = (struct nhash_list*)xxcalloc(nhash_tablesize,sizeof(struct nhash_list));
+    for (i=0; i < oldsize;i++) {
+        if ((oldtable+i)->size == 0) {
+            continue;
+        }
+        tableptr = oldtable+i;
+        for ( ; tableptr != NULL; (tableptr = tableptr->next)) {
+            /* rehash */
+            hashval = hashf(set_table+tableptr->set_offset,tableptr->size);
+            ntableptr = table+hashval;
+            if (ntableptr->size == 0) {
+                nhash_load++;
+                ntableptr->size = tableptr->size;
+                ntableptr->set_offset = tableptr->set_offset;
+                ntableptr->setnum = tableptr->setnum;
+                ntableptr->next = NULL;
+            } else {
+	        newptr = (struct nhash_list*)xxmalloc(sizeof(struct nhash_list));
+                newptr->next = ntableptr->next;
+                ntableptr->next = newptr;
+                newptr->setnum = tableptr->setnum;
+                newptr->size = tableptr->size;
+                newptr->set_offset = tableptr->set_offset;
+            }
+        }
+    }
+    nhash_free(oldtable, oldsize);
+}
+
+static void nhash_init (int initial_size) {
+
+  int i;
+
+  for (i=0; primes[i] < initial_size; i++) { }
+  nhash_load = 0;
+  nhash_tablesize = primes[i];
+  table = (struct nhash_list*)xxcalloc(nhash_tablesize , sizeof(struct nhash_list));
+  current_setnum = -1;
+}
+static void e_closure_free() {
+    int i;
+    struct e_closure_memo *eptr, *eprev;
+    xxfree(marktable);
+    for (i=0;i < num_states; i++) {
+        eptr = (e_closure_memo+i)->next;
+        for (eprev = NULL; eptr != NULL; ) {
+            eprev = eptr;
+            eptr = eptr->next;
+            xxfree(eprev);
+        }
+        
+    }
+    xxfree(e_closure_memo);
+}
+
+static void nhash_free(struct nhash_list *nptr, int size) {
+    struct nhash_list *nptr2, *nnext;
+    int i;
+    for (i=0; i < size; i++) {
+        for (nptr2 = (nptr+i)->next; nptr2 != NULL; nptr2 = nnext) {
+            nnext = nptr2->next;
+            xxfree(nptr2);
+        }
+    }
+    xxfree(nptr);
+}
diff --git a/back-ends/foma/cpp-version/dynarray.cc b/back-ends/foma/cpp-version/dynarray.cc
new file mode 100644
index 0000000..6b74fca
--- /dev/null
+++ b/back-ends/foma/cpp-version/dynarray.cc
@@ -0,0 +1,719 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2014 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "foma.h"
+
+#define INITIAL_SIZE 16384
+#define SIGMA_HASH_SIZE 1021
+#define MINSIGMA 3
+
+struct foma_reserved_symbols {
+    char *symbol;
+    int number;
+    char *prints_as;
+} foma_reserved_symbols[] = {
+    {"@_EPSILON_SYMBOL_@" , EPSILON , "0"},
+    {"@_UNKNOWN_SYMBOL_@" , UNKNOWN , "?"},
+    {"@_IDENTITY_SYMBOL_@", IDENTITY, "@"},
+    {NULL,0,NULL}
+};
+
+static size_t current_fsm_size;
+static unsigned int current_fsm_linecount, current_state_no, current_final, current_start, current_trans, num_finals, num_initials, arity, statecount;
+static Boolean is_deterministic, is_epsilon_free;
+static struct fsm_state *current_fsm_head;
+
+static unsigned int mainloop, ssize, arccount;
+
+struct sigma_lookup {
+    int target;
+    unsigned int mainloop;
+};
+
+static struct sigma_lookup *slookup;
+
+/* Functions for directly building a fsm_state structure */
+/* dynamically. */
+
+/* fsm_state_init() is called when a new machine is constructed */
+
+/* fsm_state_add_arc() adds an arc and possibly reallocs the array */
+
+/* fsm_state_close() adds the sentinel entry and clears values */
+
+struct fsm_state *fsm_state_init(int sigma_size) {
+    current_fsm_head = (struct fsm_state *)xxmalloc(INITIAL_SIZE * sizeof(struct fsm_state));
+    current_fsm_size = INITIAL_SIZE;
+    current_fsm_linecount = 0;
+    ssize = sigma_size+1;
+    slookup = (struct sigma_lookup *)xxcalloc(ssize*ssize,sizeof(struct sigma_lookup));
+    mainloop = 1;
+    is_deterministic = 1;
+    is_epsilon_free = 1;
+    arccount = 0;
+    num_finals = 0;
+    num_initials = 0;
+    statecount = 0;
+    arity = 1;
+    current_trans = 1;
+    return(current_fsm_head);
+}
+
+void fsm_state_set_current_state(int state_no, int final_state, int start_state) {
+    current_state_no = state_no;
+    current_final = final_state;
+    current_start = start_state;
+    current_trans = 0;
+    if (current_final == 1)
+        num_finals++;
+    if (current_start == 1)
+	num_initials++;
+}
+
+/* Add sentinel if needed */
+void fsm_state_end_state() {
+    if (current_trans == 0) {
+        fsm_state_add_arc(current_state_no, -1, -1, -1, current_final, current_start);
+    }
+    statecount++;
+    mainloop++;
+}
+
+void fsm_state_add_arc(int state_no, int in, int out, int target, int final_state, int start_state) {
+    struct fsm_state *cptr;
+    
+    if (in != out) {
+        arity = 2;
+    }
+    /* Check epsilon moves */
+    if (in == EPSILON && out == EPSILON) {
+        if (state_no == target) {
+            return;
+        } else {
+            is_deterministic = 0;
+            is_epsilon_free = 0;
+        }
+    }
+
+    /* Check if we already added this particular arc and skip */
+    /* Also check if net becomes non-det */
+    if (in != -1 && out != -1) {
+        if ((slookup+(ssize*in)+out)->mainloop == mainloop) {
+            if ((slookup+(ssize*in)+out)->target == target) {
+	        return;
+            } else {
+	        is_deterministic = 0;
+            }
+        }
+        arccount++;
+        (slookup+(ssize*in)+out)->mainloop = mainloop;
+        (slookup+(ssize*in)+out)->target = target;
+    }
+    
+    current_trans = 1;
+    if (current_fsm_linecount >= current_fsm_size) {
+        current_fsm_size *= 2;
+        current_fsm_head = (struct fsm_state *)xxrealloc(current_fsm_head, current_fsm_size * sizeof(struct fsm_state));
+        if (current_fsm_head == NULL) {
+            perror("Fatal error: out of memory\n");
+            exit(1);
+        }
+    }
+    cptr = current_fsm_head + current_fsm_linecount;
+    cptr->state_no = state_no;
+    cptr->in = in;
+    cptr->out = out;
+    cptr->target = target;
+    cptr->final_state = final_state;
+    cptr->start_state = start_state;
+    current_fsm_linecount++;
+}
+
+void fsm_state_close(struct fsm *net) {
+    fsm_state_add_arc(-1,-1,-1,-1,-1,-1);
+    current_fsm_head = (struct fsm_state *)xxrealloc(current_fsm_head, current_fsm_linecount * sizeof(struct fsm_state));
+    net->arity = arity;
+    net->arccount = arccount;
+    net->statecount = statecount;
+    net->linecount = current_fsm_linecount;
+    net->finalcount = num_finals;
+    net->pathcount = PATHCOUNT_UNKNOWN;
+    if (num_initials > 1)
+	is_deterministic = 0;
+    net->is_deterministic = is_deterministic;
+    net->is_pruned = UNK;
+    net->is_minimized = UNK;
+    net->is_epsilon_free = is_epsilon_free;
+    net->is_loop_free = UNK;
+    net->is_completed = UNK;
+    net->arcs_sorted_in = 0;
+    net->arcs_sorted_out = 0;
+
+    net->states = current_fsm_head;
+    xxfree(slookup);
+}
+
+/* Construction functions */
+
+struct fsm_construct_handle *fsm_construct_init(char *name) {
+    struct fsm_construct_handle *handle;
+    handle = (struct fsm_construct_handle *)xxmalloc(sizeof(struct fsm_construct_handle));
+    handle->fsm_state_list = (struct fsm_state_list *)xxcalloc(1024,sizeof(struct fsm_state_list));
+    handle->fsm_state_list_size = 1024;
+    handle->fsm_sigma_list = (struct fsm_sigma_list *)xxcalloc(1024,sizeof(struct fsm_sigma_list));
+    handle->fsm_sigma_list_size = 1024;
+    handle->fsm_sigma_hash = (struct fsm_sigma_hash *)xxcalloc(SIGMA_HASH_SIZE,sizeof(struct fsm_sigma_hash));
+    handle->maxstate = -1;
+    handle->maxsigma = -1;
+    handle->numfinals = 0;
+    if (name == NULL) {
+        handle->name = NULL;
+    } else {
+        handle->name = xxstrdup(name);
+    }
+    handle->hasinitial = 0;
+    return(handle);
+}
+
+void fsm_construct_check_size(struct fsm_construct_handle *handle, int state_no) {
+    int i, oldsize, newsize;
+    struct fsm_state_list *sl;
+    oldsize = handle->fsm_state_list_size;
+    if (oldsize <= state_no) {
+        newsize = next_power_of_two(state_no);
+        handle->fsm_state_list = (struct fsm_state_list *)xxrealloc(handle->fsm_state_list, newsize*sizeof(struct fsm_state_list));
+        handle->fsm_state_list_size = newsize;
+        sl = handle->fsm_state_list;
+        for (i=oldsize; i<newsize;i++) {
+            (sl+i)->is_final = 0;
+            (sl+i)->is_initial = 0;
+            (sl+i)->used = 0;
+            (sl+i)->num_trans = 0;
+            (sl+i)->fsm_trans_list = NULL;
+        }
+    }
+}
+
+void fsm_construct_set_final(struct fsm_construct_handle *handle, int state_no) {
+    struct fsm_state_list *sl;
+    fsm_construct_check_size(handle, state_no);
+
+    if (state_no > handle->maxstate)
+        handle->maxstate = state_no;
+
+    sl = handle->fsm_state_list;
+    if (!(sl+state_no)->is_final) {
+        (sl+state_no)->is_final = 1;
+        handle->numfinals++;
+    }
+}
+
+void fsm_construct_set_initial(struct fsm_construct_handle *handle, int state_no) {
+    struct fsm_state_list *sl;
+    fsm_construct_check_size(handle, state_no);
+
+    if (state_no > handle->maxstate)
+        handle->maxstate = state_no;
+
+    sl = handle->fsm_state_list;
+    (sl+state_no)->is_initial = 1;
+    handle->hasinitial = 1;
+}
+
+void fsm_construct_add_arc(struct fsm_construct_handle *handle, int source, int target, char *in, char *out) {
+    struct fsm_state_list *sl;
+    struct fsm_trans_list *tl;
+    int symin, symout;
+    fsm_construct_check_size(handle, source);
+    fsm_construct_check_size(handle, target);
+
+    if (source > handle->maxstate)
+        handle->maxstate = source;
+    if (target > handle->maxstate)
+        handle->maxstate = target;
+
+    sl = (handle->fsm_state_list)+target;
+    sl->used = 1;
+    sl = (handle->fsm_state_list)+source;
+    sl->used = 1;
+    tl = (struct fsm_trans_list *)xxmalloc(sizeof(struct fsm_trans_list));
+    tl->next = sl->fsm_trans_list;
+    sl->fsm_trans_list = tl;
+    if ((symin = fsm_construct_check_symbol(handle,in)) == -1)
+        symin = fsm_construct_add_symbol(handle,in);
+    if ((symout = fsm_construct_check_symbol(handle,out)) == -1)
+        symout = fsm_construct_add_symbol(handle,out);
+    tl->in = symin;
+    tl->out = symout;
+    tl->target = target;
+}
+
+unsigned int fsm_construct_hash_sym(char *symbol) {
+    register unsigned int hash;
+    hash = 0;
+    
+    while (*symbol != '\0')
+        hash = hash +  *symbol++;
+    return (hash % SIGMA_HASH_SIZE);
+}
+
+void fsm_construct_add_arc_nums(struct fsm_construct_handle *handle, int source, int target, int in, int out) {
+    struct fsm_state_list *sl;
+    struct fsm_trans_list *tl;
+    fsm_construct_check_size(handle, source);
+    fsm_construct_check_size(handle, target);
+
+    if (source > handle->maxstate)
+        handle->maxstate = source;
+    if (target > handle->maxstate)
+        handle->maxstate = target;
+
+    sl = (handle->fsm_state_list)+target;
+    sl->used = 1;
+    sl = (handle->fsm_state_list)+source;
+    sl->used = 1;
+    tl = (struct fsm_trans_list *)xxmalloc(sizeof(struct fsm_trans_list));
+    tl->next = sl->fsm_trans_list;
+    sl->fsm_trans_list = tl;
+    tl->in = in;
+    tl->out = out;
+    tl->target = target;
+}
+
+/* Copies entire alphabet from existing network */
+
+void fsm_construct_copy_sigma(struct fsm_construct_handle *handle, struct sigma *sigma) {
+
+    unsigned int hash;
+    int symnum;
+    struct fsm_sigma_hash *fh, *newfh;
+    char *symbol, *symdup;
+
+    for (; sigma != NULL && sigma->number != -1; sigma = sigma->next) {
+	symnum = sigma->number;
+	if (symnum > handle->maxsigma) {
+	    handle->maxsigma = symnum;
+	}
+	symbol = sigma->symbol;
+	if (symnum >= handle->fsm_sigma_list_size) {
+	    handle->fsm_sigma_list_size = next_power_of_two(handle->fsm_sigma_list_size);
+	    handle->fsm_sigma_list = (struct fsm_sigma_list *)xxrealloc(handle->fsm_sigma_list, (handle->fsm_sigma_list_size) * sizeof(struct fsm_sigma_list));
+	}
+	/* Insert into list */
+	symdup = xxstrdup(symbol);
+	((handle->fsm_sigma_list)+symnum)->symbol = symdup;
+	
+	/* Insert into hashtable */
+	hash = fsm_construct_hash_sym(symbol);
+	fh = (handle->fsm_sigma_hash)+hash;
+	if (fh->symbol == NULL) {
+	    fh->symbol = symdup;
+	    fh->sym = symnum;
+	} else {
+	    newfh = (struct fsm_sigma_hash *)xxcalloc(1,sizeof(struct fsm_sigma_hash));
+	    newfh->next = fh->next;
+	    fh->next = newfh;
+	    newfh->symbol = symdup;
+	    newfh->sym = symnum;
+	}
+    }
+}
+
+int fsm_construct_add_symbol(struct fsm_construct_handle *handle, char *symbol) {
+    int i, symnum, reserved;
+    unsigned int hash;
+    struct fsm_sigma_hash *fh, *newfh;
+    char *symdup;
+
+    /* Is symbol reserved? */
+    for (i=0, reserved = 0; foma_reserved_symbols[i].symbol != NULL; i++) {
+        if (strcmp(symbol, foma_reserved_symbols[i].symbol) == 0) {
+            symnum = foma_reserved_symbols[i].number;
+            reserved = 1;
+            if (handle->maxsigma < symnum) {
+                handle->maxsigma = symnum;
+            }
+            break;
+        }
+    }
+
+    if (reserved == 0) {
+        symnum = handle->maxsigma + 1;
+        if (symnum < MINSIGMA)
+            symnum = MINSIGMA;
+        handle->maxsigma = symnum;
+    }
+
+    if (symnum >= handle->fsm_sigma_list_size) {
+        handle->fsm_sigma_list_size = next_power_of_two(handle->fsm_sigma_list_size);
+        handle->fsm_sigma_list = (struct fsm_sigma_list *)xxrealloc(handle->fsm_sigma_list, (handle->fsm_sigma_list_size) * sizeof(struct fsm_sigma_list));
+    }
+    /* Insert into list */
+    symdup = xxstrdup(symbol);
+    ((handle->fsm_sigma_list)+symnum)->symbol = symdup;
+
+    /* Insert into hashtable */
+    hash = fsm_construct_hash_sym(symbol);
+    fh = (handle->fsm_sigma_hash)+hash;
+    if (fh->symbol == NULL) {
+        fh->symbol = symdup;
+        fh->sym = symnum;
+    } else {
+        newfh = (struct fsm_sigma_hash *)xxcalloc(1,sizeof(struct fsm_sigma_hash));
+        newfh->next = fh->next;
+        fh->next = newfh;
+        newfh->symbol = symdup;
+        newfh->sym = symnum;
+    }
+    return symnum;
+}
+
+int fsm_construct_check_symbol(struct fsm_construct_handle *handle, char *symbol) {
+    int hash;
+    struct fsm_sigma_hash *fh;
+    hash = fsm_construct_hash_sym(symbol);
+    fh = (handle->fsm_sigma_hash)+hash;
+    if (fh->symbol == NULL)
+        return -1;
+    for (; fh != NULL; fh = fh->next) {
+        if (strcmp(symbol,fh->symbol) == 0) {
+            return (fh->sym);
+        }
+    }
+    return -1;
+}
+
+struct sigma *fsm_construct_convert_sigma(struct fsm_construct_handle *handle) {
+    struct fsm_sigma_list *sl;
+    struct sigma *sigma, *oldsigma, *newsigma;
+    int i;
+    oldsigma = sigma = NULL;
+    sl = handle->fsm_sigma_list;
+    for (i=0; i <= handle->maxsigma; i++) {
+        if ((sl+i)->symbol != NULL) {
+            newsigma = (struct sigma *)xxmalloc(sizeof(struct sigma));
+            newsigma->number = i;
+            newsigma->symbol = (sl+i)->symbol;
+            newsigma->next = NULL;
+            if (oldsigma != NULL) {
+                oldsigma->next = newsigma;
+            } else {
+                sigma = newsigma;
+            }
+            oldsigma = newsigma;
+        }
+    }
+    return(sigma);
+}
+
+struct fsm *fsm_construct_done(struct fsm_construct_handle *handle) {
+    int i, emptyfsm;
+    struct fsm *net;
+    struct fsm_state_list *sl;
+    struct fsm_trans_list *trans, *transnext;
+    struct fsm_sigma_hash *sigmahash, *sigmahashnext;
+
+    sl = handle->fsm_state_list;
+    if (handle->maxstate == -1 || handle->numfinals == 0 || handle->hasinitial == 0) {
+        return(fsm_empty_set());
+    }
+    fsm_state_init((handle->maxsigma)+1);
+
+    for (i=0, emptyfsm = 1; i <= handle->maxstate; i++) {
+        fsm_state_set_current_state(i, (sl+i)->is_final, (sl+i)->is_initial);
+	if ((sl+i)->is_initial && (sl+i)->is_final)
+	    emptyfsm = 0; /* We want to keep track of if FSM has (a) something outgoing from initial, or (b) initial is final */
+        for (trans = (sl+i)->fsm_trans_list; trans != NULL; trans = trans->next) {
+	    if ((sl+i)->is_initial)
+		emptyfsm = 0;
+            fsm_state_add_arc(i, trans->in, trans->out, trans->target, (sl+i)->is_final, (sl+i)->is_initial);
+        }
+        fsm_state_end_state();
+    }
+    net = fsm_create("");
+    sprintf(net->name, "%X",rand());
+    xxfree(net->sigma);
+    fsm_state_close(net);
+    
+    net->sigma = fsm_construct_convert_sigma(handle);
+    if (handle->name != NULL) {
+        strncpy(net->name, handle->name, 40);
+        xxfree(handle->name);
+    } else {
+        sprintf(net->name, "%X",rand());
+    }
+
+    /* Free transitions */
+    for (i=0; i < handle->fsm_state_list_size; i++) {
+        trans = (((handle->fsm_state_list)+i)->fsm_trans_list);
+        while (trans != NULL) {
+            transnext = trans->next;
+            xxfree(trans);
+            trans = transnext;
+        }
+    }
+    /* Free hash table */
+    for (i=0; i < SIGMA_HASH_SIZE; i++) {
+        sigmahash = (((handle->fsm_sigma_hash)+i)->next);
+        while (sigmahash != NULL) {
+            sigmahashnext = sigmahash->next;
+            xxfree(sigmahash);
+            sigmahash = sigmahashnext;
+        }
+    }
+    xxfree(handle->fsm_sigma_list);
+    xxfree(handle->fsm_sigma_hash);
+    xxfree(handle->fsm_state_list);
+    xxfree(handle);
+    sigma_sort(net);
+    if (emptyfsm) {
+	fsm_destroy(net);
+	return(fsm_empty_set());
+    }
+    return(net);
+}
+
+/* Reading functions */
+
+int fsm_read_is_final(struct fsm_read_handle *h, int state) {
+    return (*((h->lookuptable)+state) & 2);
+}
+
+int fsm_read_is_initial(struct fsm_read_handle *h, int state) {
+    return (*((h->lookuptable)+state) & 1);
+}
+
+struct fsm_read_handle *fsm_read_init(struct fsm *net) {
+    struct fsm_read_handle *handle;
+    struct fsm_state *fsm, **states_head;
+    int i, j, k, num_states, num_initials, num_finals, sno, *finals_head, *initials_head, laststate;
+
+    unsigned char *lookuptable;
+    if (net == NULL) {return (NULL);}
+
+    num_states = net->statecount;
+    lookuptable = (unsigned char *)xxcalloc(num_states, sizeof(unsigned char));
+    
+    num_initials = num_finals = 0;
+
+    handle = (struct fsm_read_handle *)xxcalloc(1,sizeof(struct fsm_read_handle));
+    states_head = (struct fsm_state **)xxcalloc(num_states+1,sizeof(struct fsm **));
+
+    laststate = -1;
+    for (i=0, fsm=net->states; (fsm+i)->state_no != -1; i++) {
+        sno = (fsm+i)->state_no;
+        if ((fsm+i)->start_state) {
+            if (!(*(lookuptable+sno) & 1)) {
+                *(lookuptable+sno) |= 1;
+                num_initials++;
+            }
+            
+        }
+        if ((fsm+i)->final_state) {
+            if (!(*(lookuptable+sno) & 2)) {
+                *(lookuptable+sno) |= 2;
+                num_finals++;
+            }
+        }
+	if ((fsm+i)->in == UNKNOWN || (fsm+i)->out == UNKNOWN || (fsm+i)->in == IDENTITY || (fsm+i)->out == IDENTITY) {
+	    handle->has_unknowns = 1;
+	}
+	if ((fsm+i)->state_no != laststate) {
+	    *(states_head+(fsm+i)->state_no) = fsm+i;
+	}
+	laststate = (fsm+i)->state_no;
+    }
+    
+    finals_head = (int *)xxcalloc(num_finals+1,sizeof(int));
+    initials_head = (int *)xxcalloc(num_initials+1,sizeof(int));
+
+
+    for (i=j=k=0; i < num_states; i++) {
+        if (*(lookuptable+i) & 1) {
+            *(initials_head+j) = i;
+            j++;
+        }
+        if (*(lookuptable+i) & 2) {
+            *(finals_head+k) = i;
+            k++;
+        }
+    }
+    *(initials_head+j) = -1;
+    *(finals_head+k) = -1;
+    
+    handle->finals_head = finals_head;
+    handle->initials_head = initials_head;
+    handle->states_head = states_head;
+    
+    handle->fsm_sigma_list = sigma_to_list(net->sigma);
+    handle->sigma_list_size = sigma_max(net->sigma)+1;
+    handle->arcs_head = fsm;
+    handle->lookuptable = lookuptable;
+    handle->net = net;
+    return(handle);
+}
+
+void fsm_read_reset(struct fsm_read_handle *handle) {
+    if (handle == NULL)
+	return;
+    handle->arcs_cursor = NULL;
+    handle->initials_cursor = NULL;
+    handle->finals_cursor = NULL;
+    handle->states_cursor = NULL;
+}
+
+int fsm_get_next_state_arc(struct fsm_read_handle *handle) {
+    handle->arcs_cursor++;
+    if ((handle->arcs_cursor->state_no != handle->current_state) || (handle->arcs_cursor->target == -1)) {
+	handle->arcs_cursor--;
+	return 0;
+    }
+    return 1;
+}
+
+int fsm_get_next_arc(struct fsm_read_handle *handle) {
+    if (handle->arcs_cursor == NULL) {
+        handle->arcs_cursor = handle->arcs_head;
+        while (handle->arcs_cursor->state_no != -1 && handle->arcs_cursor->target == -1) {
+            handle->arcs_cursor++;
+        }
+        if (handle->arcs_cursor->state_no == -1) {
+            return 0;
+        }
+    } else {
+        if (handle->arcs_cursor->state_no == -1) {
+            return 0;
+        }
+        do {
+            handle->arcs_cursor++;
+        } while (handle->arcs_cursor->state_no != -1 && handle->arcs_cursor->target == -1);
+        if (handle->arcs_cursor->state_no == -1) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int fsm_get_arc_source(struct fsm_read_handle *handle) {
+    if (handle->arcs_cursor == NULL) { return -1;}
+    return(handle->arcs_cursor->state_no);
+}
+
+int fsm_get_arc_target(struct fsm_read_handle *handle) {
+    if (handle->arcs_cursor == NULL) { return -1;}
+    return(handle->arcs_cursor->target);
+}
+
+int fsm_get_symbol_number(struct fsm_read_handle *handle, char *symbol) {
+    int i;
+    for (i=0; i < handle->sigma_list_size; i++) {
+	if ((handle->fsm_sigma_list+i)->symbol == NULL)
+	    continue;
+	if (strcmp(symbol,  (handle->fsm_sigma_list+i)->symbol) == 0) {
+	    return i;
+	}
+    }
+    return -1;
+}
+
+char *fsm_get_arc_in(struct fsm_read_handle *handle) {
+    int index;
+    char *sym;
+    if (handle->arcs_cursor == NULL) { return NULL;}
+    index = handle->arcs_cursor->in;
+    sym = (handle->fsm_sigma_list+index)->symbol;
+    return(sym);
+}
+
+int fsm_get_arc_num_in(struct fsm_read_handle *handle) {
+    if (handle->arcs_cursor == NULL) { return -1;}
+    return(handle->arcs_cursor->in);
+}
+
+int fsm_get_arc_num_out(struct fsm_read_handle *handle) {
+    if (handle->arcs_cursor == NULL) { return -1;}
+    return(handle->arcs_cursor->out);
+}
+
+char *fsm_get_arc_out(struct fsm_read_handle *handle) {
+    int index;
+    char *sym;
+    if (handle->arcs_cursor == NULL) { return NULL; }
+    index = handle->arcs_cursor->out;
+    sym = (handle->fsm_sigma_list+index)->symbol;
+    return(sym);
+}
+
+int fsm_get_next_initial(struct fsm_read_handle *handle) {
+    if (handle->initials_cursor == NULL) {
+        handle->initials_cursor = handle->initials_head;
+    } else {
+        if (*(handle->initials_cursor) == -1) {
+            return -1;
+        }
+        handle->initials_cursor++;
+    }
+    return *(handle->initials_cursor);
+}
+
+int fsm_get_next_final(struct fsm_read_handle *handle) {
+    if (handle->finals_cursor == NULL) {
+        handle->finals_cursor = handle->finals_head;
+    } else {
+        if (*(handle->finals_cursor) == -1) {
+            return -1;
+        }
+        handle->finals_cursor++;
+    }
+    return *(handle->finals_cursor);
+}
+
+int fsm_get_num_states(struct fsm_read_handle *handle) {
+    return(handle->net->statecount);
+}
+
+int fsm_get_has_unknowns(struct fsm_read_handle *handle) {
+    return(handle->has_unknowns);
+}
+
+int fsm_get_next_state(struct fsm_read_handle *handle) {
+    int stateno;
+    if (handle->states_cursor == NULL) {
+        handle->states_cursor = handle->states_head;
+    } else {
+	handle->states_cursor++;
+    }
+    if (handle->states_cursor - handle->states_head >= fsm_get_num_states(handle)) {
+	return -1;
+    }
+    handle->arcs_cursor = *(handle->states_cursor);
+    stateno = (*(handle->states_cursor))->state_no;
+    handle->arcs_cursor--;
+    handle->current_state = stateno;
+    return (stateno);
+}
+
+void fsm_read_done(struct fsm_read_handle *handle) {
+    xxfree(handle->lookuptable);
+    xxfree(handle->fsm_sigma_list);
+    xxfree(handle->finals_head);
+    xxfree(handle->initials_head);
+    xxfree(handle->states_head);
+    xxfree(handle);
+}
diff --git a/back-ends/foma/cpp-version/extract.cc b/back-ends/foma/cpp-version/extract.cc
new file mode 100644
index 0000000..fea08d2
--- /dev/null
+++ b/back-ends/foma/cpp-version/extract.cc
@@ -0,0 +1,71 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdlib.h>
+#include "foma.h"
+
+struct fsm *fsm_lower(struct fsm *net) {
+    struct fsm_state *fsm;
+    int i, prevstate, out;
+    fsm = net->states;
+    fsm_state_init(sigma_max(net->sigma));
+    prevstate = -1;
+    for (i = 0; (fsm+i)->state_no != - 1; prevstate = (fsm+i)->state_no, i++) {
+        if (prevstate != -1 && prevstate != (fsm+i)->state_no) {
+            fsm_state_end_state();
+        }
+        if (prevstate != (fsm+i)->state_no) {
+            fsm_state_set_current_state((fsm+i)->state_no, (fsm+i)->final_state, (fsm+i)->start_state);
+        }
+        if ((fsm+i)->target != -1) {
+            out = ((fsm+i)->out == UNKNOWN) ? IDENTITY : (fsm+i)->out;
+            fsm_state_add_arc((fsm+i)->state_no, out, out, (fsm+i)->target, (fsm+i)->final_state, (fsm+i)->start_state);
+        }
+    }
+    fsm_state_end_state();
+    xxfree(net->states);
+    fsm_state_close(net);
+    fsm_update_flags(net,NO,NO,NO,UNK,UNK,UNK);
+    sigma_cleanup(net,0);
+    return(net);
+}
+
+struct fsm *fsm_upper(struct fsm *net) {
+    struct fsm_state *fsm;
+    int i, prevstate, in;
+    fsm = net->states;
+    fsm_state_init(sigma_max(net->sigma));
+    prevstate = -1;
+    for (i = 0; (fsm+i)->state_no != - 1; prevstate = (fsm+i)->state_no, i++) {
+        if (prevstate != -1 && prevstate != (fsm+i)->state_no) {
+            fsm_state_end_state();
+        }
+        if (prevstate != (fsm+i)->state_no) {
+            fsm_state_set_current_state((fsm+i)->state_no, (fsm+i)->final_state, (fsm+i)->start_state);
+        }
+        if ((fsm+i)->target != -1) {
+            in = ((fsm+i)->in == UNKNOWN) ? IDENTITY : (fsm+i)->in;
+            fsm_state_add_arc((fsm+i)->state_no, in, in, (fsm+i)->target, (fsm+i)->final_state, (fsm+i)->start_state);
+        }
+    }
+    fsm_state_end_state();
+    xxfree(net->states);
+    fsm_state_close(net);
+    fsm_update_flags(net,NO,NO,NO,UNK,UNK,UNK);
+    sigma_cleanup(net,0);
+    return(net);
+}
diff --git a/back-ends/foma/cpp-version/flags.cc b/back-ends/foma/cpp-version/flags.cc
new file mode 100644
index 0000000..1972fd5
--- /dev/null
+++ b/back-ends/foma/cpp-version/flags.cc
@@ -0,0 +1,522 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2011 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include "foma.h"
+
+#define FAIL    1
+#define SUCCEED 2
+#define NONE    3
+
+static struct flags *flag_extract (struct fsm *net);
+static char *flag_type_to_char (int type);
+static void flag_purge (struct fsm *net, char *name);
+static struct fsm *flag_create_symbol(int type, char *name, char *value);
+
+struct flags {
+    int type;
+    char *name;
+    char *value;
+    struct flags *next;
+};
+
+/* We eliminate all flags by creating a list of them and building a regex filter   */
+/* that successively removes unwanted paths.  NB: flag_eliminate() called with the */
+/* second argument NULL eliminates all flags.                                      */
+/* The regexes we build for each flag symbol are of the format:                    */
+/* ~[?* FAIL ~$SUCCEED THISFLAG ?*] for U,P,D                                      */
+/* or                                                                              */
+/* ~[(?* FAIL) ~$SUCCEED THISFLAG ?*] for the R flag                               */
+/* The function flag_build() determines, depending on the flag at hand for each    */
+/* of the other flags occurring in the network if it belongs in FAIL, SUCCEED,     */
+/* or neither.                                                                     */
+/* The languages FAIL, SUCCEED is then the union of all symbols that cause         */
+/* compatibility or incompatibility.                                               */
+/* We intersect all these filters, creating a large filter that we compose both on */
+/* the upper side of the network and the lower side:                               */
+/* RESULT = FILTER .o. ORIGINAL .o. FILTER                                         */
+/* We can't simply intersect the language with FILTER because the lower side flags */
+/* are independent of the upper side ones, and the network may be a transducer.    */
+/* Finally, we replace the affected arcs with EPSILON arcs, and call               */
+/* sigma_cleanup() to purge the symbols not occurring on arcs.                     */
+
+///
+///Eliminate a flag from a network. If called with name = NULL, eliminate all flags.
+///
+
+struct fsm *flag_eliminate(struct fsm *net, char *name) {
+
+    struct flags *flags, *f, *ff;
+    struct fsm *filter, *succeed_flags, *fail_flags, *self, *newfilter, *newnet;
+    int flag, fstatus, found;
+
+    filter = NULL;
+
+    flags = flag_extract(net);
+    /* Check that flag actually exists in net */
+    if (name != NULL) {
+        for (found = 0, f = flags; f != NULL; f = f->next) {
+            if (strcmp(name,f->name) == 0)
+                found = 1;
+        }
+        if (found == 0) {
+#ifdef ORIGINAL
+	    fprintf(stderr,"Flag attribute '%s' does not occur in the network.\n",name);
+#else
+            // TODO: Handle this in some other way.
+#endif
+            return(net);
+        }
+    }
+
+    flag = 0;
+
+    for (f = flags; f != NULL; f = f->next) {
+
+        if ((name == NULL || strcmp(f->name,name) == 0) &&
+            (f->type | FLAG_UNIFY | FLAG_REQUIRE | FLAG_DISALLOW | FLAG_EQUAL)) {
+            
+            succeed_flags = fsm_empty_set();
+            fail_flags = fsm_empty_set();
+            self = flag_create_symbol(f->type, f->name, f->value);
+            
+            for (ff = flags, flag = 0; ff != NULL; ff = ff->next) {
+                fstatus = flag_build(f->type, f->name, f->value, ff->type, ff->name, ff->value);
+                if (fstatus == FAIL) {
+                    fail_flags = fsm_minimize(fsm_union(fail_flags, flag_create_symbol(ff->type, ff->name, ff->value)));
+                    flag = 1;
+                }
+                if (fstatus == SUCCEED) {
+                    succeed_flags = fsm_minimize(fsm_union(succeed_flags, flag_create_symbol(ff->type, ff->name, ff->value)));
+                    flag = 1;
+                }
+            }
+        }
+
+        if (flag) {
+            if (f->type == FLAG_REQUIRE) {
+                newfilter = fsm_complement(fsm_concat(fsm_optionality(fsm_concat(fsm_universal(), fail_flags)), fsm_concat(fsm_complement(fsm_contains(succeed_flags)), fsm_concat(self, fsm_universal()))));
+                
+            } else {
+                newfilter = fsm_complement(fsm_contains(fsm_concat(fail_flags,fsm_concat(fsm_complement(fsm_contains(succeed_flags)),self))));
+            }
+
+            filter = (filter == NULL) ? newfilter : fsm_intersect(filter, newfilter);
+        }
+        flag = 0;
+    }
+    if (filter != NULL) {
+        extern int g_flag_is_epsilon;
+        int old_g_flag_is_epsilon;
+        old_g_flag_is_epsilon = g_flag_is_epsilon;
+        g_flag_is_epsilon = 0;
+        newnet = fsm_compose(fsm_copy(filter),fsm_compose(net,fsm_copy(filter)));
+        g_flag_is_epsilon = old_g_flag_is_epsilon;
+    } else {
+        newnet = net;
+    }
+    flag_purge(newnet, name);
+    newnet = fsm_minimize(newnet);
+    sigma_cleanup(newnet,0);
+    xxfree(flags);
+    return(fsm_topsort(newnet));
+}
+
+struct fsm *flag_create_symbol(int type, char *name, char *value) {
+    char *string;
+    if (value == NULL)
+        value = "";
+
+    string = (char*)xxmalloc(sizeof(char)*strlen(name)+strlen(value)+6);
+    *string = '\0';
+    strcat(string, "@");
+    strcat(string, flag_type_to_char(type));
+    strcat(string, ".");
+    strcat(string, name);
+    if (strcmp(value,"") != 0) {
+        strcat(string, ".");
+        strcat(string, value);
+    }
+    strcat(string, "@");
+
+    return(fsm_symbol(string));
+
+}
+
+char *flag_type_to_char (int type) {
+    switch(type) {
+    case FLAG_UNIFY:
+        return("U");
+    case FLAG_CLEAR:
+        return("C");
+    case FLAG_DISALLOW:
+        return("D");
+    case FLAG_NEGATIVE:
+        return("N");
+    case FLAG_POSITIVE:
+        return("P");
+    case FLAG_REQUIRE:
+        return("R");
+    case FLAG_EQUAL:
+        return("E");
+    }
+    return NULL;
+}
+
+int flag_build(int ftype, char *fname, char *fvalue, int fftype, char *ffname, char *ffvalue) {
+    int valeq, selfnull;
+
+    selfnull = 0; /* If current flag has no value, e.g. @R.A@ */
+    if (strcmp(fname,ffname) != 0)
+        return NONE;
+    
+    if (fvalue == NULL) {
+        fvalue = "";
+        selfnull = 1;
+    }
+    
+    if (ffvalue == NULL)
+        ffvalue = "";
+
+    valeq = strcmp(fvalue, ffvalue);
+    /* U flags */
+    if (ftype == FLAG_UNIFY && fftype == FLAG_POSITIVE && valeq == 0)
+        return SUCCEED;
+    if (ftype == FLAG_UNIFY && fftype == FLAG_CLEAR)
+        return SUCCEED;
+    if (ftype == FLAG_UNIFY && fftype == FLAG_UNIFY && valeq != 0)
+        return FAIL;
+    if (ftype == FLAG_UNIFY && fftype == FLAG_POSITIVE && valeq != 0)
+        return FAIL;
+    if (ftype == FLAG_UNIFY && fftype == FLAG_NEGATIVE && valeq == 0)
+        return FAIL;
+
+    /* R flag with value = 0 */
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_UNIFY && selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_POSITIVE && selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_NEGATIVE && selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_CLEAR && selfnull)
+        return FAIL;
+
+    /* R flag with value */
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_POSITIVE && valeq == 0 && !selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_UNIFY && valeq == 0 && !selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_POSITIVE && valeq != 0 && !selfnull)
+        return FAIL;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_UNIFY && valeq != 0 && !selfnull)
+        return FAIL;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_NEGATIVE && !selfnull)
+        return FAIL;
+    if (ftype == FLAG_REQUIRE && fftype == FLAG_CLEAR && !selfnull)
+        return FAIL;
+
+    /* D flag with value = 0 */
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_CLEAR && selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_POSITIVE && selfnull)
+        return FAIL;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_UNIFY && selfnull)
+        return FAIL;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_NEGATIVE && selfnull)
+        return FAIL;
+
+    /* D flag with value */
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_POSITIVE && valeq != 0 && !selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_CLEAR && !selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_NEGATIVE  && valeq == 0 && !selfnull)
+        return SUCCEED;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_POSITIVE && valeq == 0 && !selfnull)
+        return FAIL;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_UNIFY && valeq == 0 && !selfnull)
+        return FAIL;
+    if (ftype == FLAG_DISALLOW && fftype == FLAG_NEGATIVE  && valeq != 0 && !selfnull)
+        return FAIL;
+
+    return NONE;
+}
+
+
+/* Remove flags that are being eliminated from arcs and sigma */
+
+void flag_purge (struct fsm *net, char *name) {
+    struct fsm_state *fsm;
+    struct sigma *sigma;
+    int i, *ftable, sigmasize;
+    char *csym;
+    sigmasize = sigma_max(net->sigma)+1;
+    ftable = (int*)xxmalloc(sizeof(int) * sigmasize);
+    fsm = net->states;
+    for (i=0; i<sigmasize; i++)
+        *(ftable+i)=0;
+    
+    for (sigma = net->sigma; sigma != NULL && sigma->number != -1; sigma = sigma->next) {
+        
+        if (flag_check(sigma->symbol)) {
+            if (name == NULL) {
+                *(ftable+(sigma->number)) = 1;
+            } else {
+                csym = (sigma->symbol) + 3;
+                if (strncmp(csym,name,strlen(name)) == 0 && (strlen(csym)>strlen(name)) && (strncmp(csym+strlen(name),".",1) == 0 || strncmp(csym+strlen(name),"@",1) == 0)) {
+                    *(ftable+(sigma->number)) = 1;
+                }
+            }
+        }
+    }
+    for (i = 0; i < sigmasize; i++) {
+	if (*(ftable+i)) {
+	    net->sigma = sigma_remove_num(i, net->sigma);
+	}
+    }
+
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->in >= 0 && (fsm+i)->out >= 0) {
+            if (*(ftable+(fsm+i)->in))
+                (fsm+i)->in = EPSILON;
+            if (*(ftable+(fsm+i)->out))
+                (fsm+i)->out = EPSILON;
+        }
+    }
+
+    xxfree(ftable);
+    net->is_deterministic = net->is_minimized = net->is_epsilon_free = NO;
+    return;
+}
+
+/* Extract all flags from network and place them in struct flag linked list */
+
+struct flags *flag_extract (struct fsm *net) {
+    struct sigma *sigma;
+    struct flags *flags, *flagst;
+
+    flags = NULL;
+    for (sigma = net->sigma ; sigma != NULL; sigma = sigma->next) {
+        if (flag_check(sigma->symbol)) {
+	    flagst = (struct flags*)xxmalloc(sizeof(struct flags));
+            flagst->next = flags;
+            flags = flagst;
+            
+            flags->type  = flag_get_type(sigma->symbol);
+            flags->name  = flag_get_name(sigma->symbol);
+            flags->value = flag_get_value(sigma->symbol);
+        }
+    }
+    return(flags);
+}
+
+int flag_check(char *s) {
+    
+    /* We simply simulate this regex (where ND is not dot) */
+    /* "@" [U|P|N|R|E|D] "." ND+ "." ND+ "@" | "@" [D|R|C] "." ND+ "@" */
+    /* and return 1 if it matches */
+
+    int i;
+    i = 0;
+    
+    if (*(s+i) == '@') { i++; goto s1; } return 0;
+ s1:
+    if (*(s+i) == 'C') { i++; goto s4; }
+    if (*(s+i) == 'N' || *(s+i) == 'E' || *(s+i) == 'U' || *(s+i) == 'P') { i++; goto s2; }
+    if (*(s+i) == 'R' || *(s+i) == 'D') { i++; goto s3; } return 0;
+ s2:
+    if (*(s+i) == '.') { i++; goto s5; } return 0;
+ s3:
+    if (*(s+i) == '.') { i++; goto s6; } return 0;
+ s4:
+    if (*(s+i) == '.') { i++; goto s7; } return 0;
+ s5:
+    if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s8; } return 0;
+ s6:
+    if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s9; } return 0;
+ s7:
+    if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s10; } return 0;
+ s8:
+   if (*(s+i) == '.') { i++; goto s7; }
+   if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s8; } return 0;
+ s9:
+    if (*(s+i) == '@') { i++; goto s11; }
+    if (*(s+i) == '.') { i++; goto s7; }
+    if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s9; } return 0;
+
+ s10:
+    if (*(s+i) == '@') {i++; goto s11;}
+    if (*(s+i) != '.' && *(s+i) != '\0') { i++; goto s10; } return 0;
+ s11:
+    if (*(s+i) == '\0') {return 1;} return 0;
+}
+
+int flag_get_type(char *string) {
+    if (strncmp(string+1,"U.",2) == 0) {
+	return FLAG_UNIFY;
+    }
+    if (strncmp(string+1,"C.",2) == 0) {
+	return FLAG_CLEAR;
+    }
+    if (strncmp(string+1,"D.",2) == 0) {
+	return FLAG_DISALLOW;
+    }
+    if (strncmp(string+1,"N.",2) == 0) {
+	return FLAG_NEGATIVE;
+    }
+    if (strncmp(string+1,"P.",2) == 0) {
+	return FLAG_POSITIVE;
+    }
+    if (strncmp(string+1,"R.",2) == 0) {
+	return FLAG_REQUIRE;
+    }
+    if (strncmp(string+1,"E.",2) == 0) {
+	return FLAG_EQUAL;
+    }
+    return 0;
+}
+
+char *flag_get_name(char *string) {
+    int i, start, end, len;
+    start = end = 0;
+    len = strlen(string);
+
+    for (i=0; i < len; i += (utf8skip(string+i) + 1)) {
+	if (*(string+i) == '.' && start == 0) {
+	    start = i+1;
+	    continue;
+	}
+	if ((*(string+i) == '.' || *(string+i) == '@')  && start != 0) {
+	    end = i;
+	    break;
+	}
+    }
+    if (start > 0 && end > 0) {
+	return(xxstrndup(string+start,end-start));
+    }
+    return NULL;
+}
+
+char *flag_get_value(char *string) {
+    int i, first, start, end, len;
+    first = start = end = 0;
+    len = strlen(string);
+
+    for (i=0; i < len; i += (utf8skip(string+i) + 1)) {
+	if (*(string+i) == '.' && first == 0) {
+	    first = i+1;
+	    continue;
+	}
+	if (*(string+i) == '@' && start != 0) {
+	    end = i;
+	    break;
+	}
+	if (*(string+i) == '.' && first != 0) {
+	    start = i+1;
+	    continue;
+	}
+    }
+    if (start > 0 && end > 0) {
+	return(xxstrndup(string+start,end-start));
+    }
+    return NULL;
+}
+
+struct fsm *flag_twosided(struct fsm *net) {
+  struct fsm_state *fsm;
+  struct sigma *sigma;
+  int i, j, tail, *isflag, maxsigma, maxstate, newarcs, change;
+ 
+  /* Enforces twosided flag diacritics */
+  
+  /* Mark flag symbols */
+  maxsigma = sigma_max(net->sigma);
+  isflag = (int*)xxcalloc(maxsigma+1, sizeof(int));
+  fsm = net->states;
+  for (sigma = net->sigma ; sigma != NULL; sigma = sigma->next) {
+    if (flag_check(sigma->symbol)) {
+      *(isflag+sigma->number) = 1;
+    } else {
+      *(isflag+sigma->number) = 0;
+    }
+  }
+  maxstate = 0;
+  change = 0;
+  for (i = 0, newarcs = 0; (fsm+i)->state_no != -1 ; i++) {
+    maxstate = (fsm+i)->state_no > maxstate ? (fsm+i)->state_no : maxstate;
+    if ((fsm+i)->target == -1)
+      continue;
+    if (*(isflag+(fsm+i)->in) && (fsm+i)->out == EPSILON) {
+      change = 1;
+      (fsm+i)->out = (fsm+i)->in;
+    }
+    else if (*(isflag+(fsm+i)->out) && (fsm+i)->in == EPSILON) {
+      change = 1;
+      (fsm+i)->in = (fsm+i)->out;
+    }
+    if ((*(isflag+(fsm+i)->in) || *(isflag+(fsm+i)->out)) && (fsm+i)->in != (fsm+i)->out) {
+      newarcs++;
+    }
+  }
+
+  if (newarcs == 0) {
+    if (change == 1) {
+      net->is_deterministic = UNK;
+      net->is_minimized = UNK;
+      net->is_pruned = UNK;
+      return fsm_topsort(fsm_minimize(net));
+    }
+    return net;
+  }
+  net->states = (struct fsm_state*)xxrealloc(net->states, sizeof(struct fsm)*(i+newarcs));
+  fsm = net->states;
+  tail = j = i;
+  maxstate++;
+  for (i = 0; i < tail; i++) {
+
+    if ((fsm+i)->target == -1)
+      continue;
+    if ((*(isflag+(fsm+i)->in) || *(isflag+(fsm+i)->out)) && (fsm+i)->in != (fsm+i)->out) {
+      if (*(isflag+(fsm+i)->in) && !*(isflag+(fsm+i)->out)) {
+	j = add_fsm_arc(fsm, j, maxstate, EPSILON, (fsm+i)->out, (fsm+i)->target, 0, 0);
+	(fsm+i)->out = (fsm+i)->in;
+	(fsm+i)->target = maxstate;
+	maxstate++;
+      }
+      else if (*(isflag+(fsm+i)->out) && !*(isflag+(fsm+i)->in)) {
+	j = add_fsm_arc(fsm, j, maxstate, (fsm+i)->out, (fsm+i)->out, (fsm+i)->target, 0, 0);
+	(fsm+i)->out = EPSILON;
+	(fsm+i)->target = maxstate;
+	maxstate++;
+      }
+      else if (*(isflag+(fsm+i)->in) && *(isflag+(fsm+i)->out)) {
+	j = add_fsm_arc(fsm, j, maxstate, (fsm+i)->out, (fsm+i)->out, (fsm+i)->target, 0, 0);
+	(fsm+i)->out = (fsm+i)->in;
+	(fsm+i)->target = maxstate;
+	maxstate++;
+      }
+    }
+  }
+  /* Add sentinel */
+  add_fsm_arc(fsm, j, -1, -1, -1, -1, -1, -1);
+  net->is_deterministic = UNK;
+  net->is_minimized = UNK;
+  return fsm_topsort(fsm_minimize(net));
+}
diff --git a/back-ends/foma/cpp-version/foma.cc b/back-ends/foma/cpp-version/foma.cc
new file mode 100644
index 0000000..bd1dade
--- /dev/null
+++ b/back-ends/foma/cpp-version/foma.cc
@@ -0,0 +1,266 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2014 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <time.h>
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+  #include <readline/readline.h>
+#endif
+#include "foma.h"
+
+/* Front-end behavior variables */
+int pipe_mode = 0;
+int quiet_mode = 0;
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+  static int use_readline = 1;
+#else
+  static int use_readline = 0;
+#endif
+
+int promptmode = PROMPT_MAIN;
+int apply_direction;
+
+/* Variable to pass the position of rl completion to our completer */
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+  static int smatch;
+#endif
+
+char *usagestring = "Usage: foma [-e \"command\"] [-f run-once-script] [-l startupscript] [-p] [-q] [-s] [-v]\n";
+
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+static char** my_completion(const char*, int ,int);
+char *my_generator(const char* , int);
+char *cmd [] = {"ambiguous upper","apply down","apply med","apply up","apropos","assert-stack","clear stack","close sigma","compact sigma","complete net","compose net","concatenate net","crossproduct net","define","determinize net","echo","eliminate flags","eliminate flag","export cmatrix","extract ambiguous","extract unambiguous","factorize","help license","help warranty","ignore net","intersect net","invert net","label net","letter machine","load defined","lower-side net","minimize net [...]
+
+char *abbrvcmd [] = {"ambiguous","close","down","up","med","size","loadd","lower-words","upper-words","net","random-lower","random-upper","words","random-words","regex","rpl","au revoir","bye","exit","saved","seq","ss","stack","tunam","tid","tfu","tlu","tuu","tnu","tnn","tseq","tsf","equ","pss","psz","ratt","tfd","hyvästi","watt","wpl","examb","exunamb","pairs","random-pairs",NULL};
+#endif
+
+/* #include "yy.tab.h" */
+
+int view_net(struct fsm *net);
+
+extern int input_is_file;
+extern int add_history (const char *);
+extern int my_yyparse(char *my_string);
+void print_help();
+void xprintf(char *string) { return ; printf("%s",string); }
+char disclaimer1[] = "Foma, version ";
+char disclaimer2[] = "\nCopyright © 2008-2015 Mans Hulden\nThis is free software; see the source code for copying conditions.\nThere is ABSOLUTELY NO WARRANTY; for details, type \"help license\"\n\nType \"help\" to list all commands available.\nType \"help <topic>\" or help \"<operator>\" for further help.\n\n";
+
+#ifndef SVN_REV
+#define SVN_REV 0
+#endif
+
+/* A static variable for holding the line. */
+
+static char *command = (char *)NULL;
+char *flex_command = NULL;
+static char *line_read = (char *)NULL;
+char no_readline_line[512];
+
+/* Read a string, and return a pointer to it.
+   Returns NULL on EOF. */
+
+char *rl_gets(char *prompt) {
+    
+    /* If the buffer has already been allocated,
+       return the memory to the free pool. */
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+    if (use_readline == 1) {
+        if (line_read) {
+            free(line_read);
+            line_read = (char *)NULL;
+        }
+    }
+    if (use_readline == 0) {
+#endif
+        printf("%s",prompt);
+        line_read = fgets(no_readline_line, 511, stdin);
+        if (line_read != NULL) {
+            strip_newline(line_read);
+        }
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+    } else {
+        line_read = readline(prompt);
+    }
+    
+    /* If the line has any text in it,
+       save it on the history. */
+    if (use_readline == 1) {
+        if (line_read && *line_read)
+            add_history(line_read);
+    }
+#endif
+    return (line_read);
+}
+
+int main(int argc, char *argv[]) {
+    int opt;
+
+    char *scriptfile, prompt[50];
+    extern void my_interfaceparse(char *my_string);
+    /*  YY_BUFFER_STATE flex_command; */
+    stack_init();
+    srand ((unsigned int)time(NULL));
+    /* Init defined_networks structures */
+    g_defines = defined_networks_init();
+    g_defines_f = defined_functions_init();
+
+    while ((opt = getopt(argc, argv, "e:f:hl:pqrsv")) != -1) {
+        switch(opt) {
+        case 'e':
+            my_interfaceparse(optarg);
+            break;
+        case 'f':
+            scriptfile = file_to_mem(optarg);
+            if (scriptfile != NULL) {
+                input_is_file = 1;
+                my_interfaceparse(scriptfile);
+            }
+            exit(0);
+        case 'h':
+            print_help();
+            exit(0);
+        case 'l':
+            scriptfile = file_to_mem(optarg);
+            if (scriptfile != NULL) {
+                input_is_file = 1;
+                my_interfaceparse(scriptfile);
+		xxfree(scriptfile);
+            }
+            break;
+        case 'p':
+            pipe_mode = 1;
+            break;
+        case 'q':
+            quiet_mode = 1;
+            break;
+        case 'r':
+            use_readline = 0;
+            break;
+        case 's':
+	  exit(0);
+        case 'v':
+            printf("%s %i.%i.%i%s\n",argv[0],MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,STATUS_VERSION);
+            exit(0);
+        default:
+            fprintf(stderr, "%s", usagestring);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (!pipe_mode && !quiet_mode)
+      printf("%s%i.%i.%i%s (svn r%i)%s",disclaimer1,MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,STATUS_VERSION,SVN_REV,disclaimer2);
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+    rl_basic_word_break_characters = " >";
+
+    rl_attempted_completion_function = my_completion;
+#endif
+    for(;;) {
+        if (promptmode == PROMPT_MAIN)
+            sprintf(prompt, "foma[%i]: ",stack_size());
+        if (promptmode == PROMPT_A && apply_direction == AP_D)
+            sprintf(prompt, "apply down> ");
+        if (promptmode == PROMPT_A && apply_direction == AP_U)
+            sprintf(prompt, "apply up> ");
+        if (promptmode == PROMPT_A && apply_direction == AP_M)
+            sprintf(prompt, "apply med> ");
+        if (pipe_mode || quiet_mode)
+	    prompt[0] = '\0';
+
+	fflush(stdout);
+	
+        command = rl_gets(prompt);
+
+        if (command == NULL && promptmode == PROMPT_MAIN) {
+            printf("\n");
+            exit(0);
+        }
+        if (command == NULL && promptmode == PROMPT_A) {
+            /* apply_clear(); */
+            promptmode = PROMPT_MAIN;
+            printf("\n");
+            continue;
+        }
+        input_is_file = 0;
+        my_interfaceparse(command);
+    }
+}
+
+void print_help() {
+    printf("%s",usagestring);
+    printf("Options:\n");
+    printf("-e \"command\"\texecute a command on startup (-e can be invoked several times)\n");
+    printf("-f scriptfile\tread commands from scriptfile on startup, and quit\n");
+    printf("-l scriptfile\tread commands from scriptfile on startup\n");
+    printf("-p\t\tpipe-mode\n");
+    printf("-q\t\tquiet mode (more quiet than pipe-mode)\n");
+    printf("-r\t\tdon't use readline library for input\n");
+    printf("-s\t\tstop execution and exit\n");
+    printf("-v\t\tprint version number\n");
+}
+
+#if defined(ORIGINAL) || defined(HAVE_READLINE)
+static char **my_completion(const char *text, int start, int end) {
+    char **matches;
+
+    matches = (char **)NULL;
+    smatch = start;
+    matches = rl_completion_matches ((char*)text, &my_generator);
+    
+    return (matches);
+}
+
+char *my_generator(const char *text, int state) {
+    static int list_index, list_index2, len, nummatches;
+    char *name;
+    text = rl_line_buffer;
+    if (!state) {
+        list_index = 0;
+        list_index2 = 0;
+        nummatches = 0;
+        len = strlen(text);
+    }
+    
+    while ((name = cmd[list_index])) {
+        list_index++;
+
+        if (strncmp (name, text, len) == 0) {
+            nummatches++;
+            /* Can't use xxstrdup here */
+            return(strdup(name+smatch));
+        }
+    }
+    
+    if (rl_point > 0) {
+        while ((name = abbrvcmd[list_index2])) {
+            list_index2++;
+            
+            /* Can't use xxstrdup here */
+            if (strncmp (name, text, len) == 0)
+                return(strdup(name+smatch));
+        }
+    }
+    
+    /* If no names matched, then return NULL. */
+    return ((char *)NULL);
+}
+#endif
diff --git a/back-ends/foma/fomalib.h b/back-ends/foma/cpp-version/fomalib.h
similarity index 99%
copy from back-ends/foma/fomalib.h
copy to back-ends/foma/cpp-version/fomalib.h
index 3a46bd2..d904956 100644
--- a/back-ends/foma/fomalib.h
+++ b/back-ends/foma/cpp-version/fomalib.h
@@ -16,7 +16,7 @@
 /*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
 
 #ifdef  __cplusplus
-extern "C" {
+//extern "C" {
 #endif
 #include <stdio.h>
 #include <inttypes.h>
@@ -38,7 +38,7 @@ extern "C" {
     #define FEXPORT __declspec(dllexport)
     #define INLINE
   #else
-    #define INLINE inline
+    #define INLINE
     #define FEXPORT __attribute__((visibility("default")))
   #endif
 #endif // #ifdef ORIGINAL
@@ -303,7 +303,7 @@ FEXPORT struct fsm *flag_eliminate(struct fsm *net, char *name);
 FEXPORT struct fsm *flag_twosided(struct fsm *net);
 
 /* Compile a rewrite rule */
-FEXPORT struct fsm *fsm_rewrite();
+FEXPORT struct fsm *fsm_rewrite(struct rewrite_set *all_rules);
 
 /* Boolean tests */
 FEXPORT int fsm_isempty(struct fsm *net);
@@ -524,5 +524,5 @@ FEXPORT int fsm_get_next_state_arc(struct fsm_read_handle *handle);
 FEXPORT void fsm_read_done(struct fsm_read_handle *handle);
 
 #ifdef  __cplusplus
-}
+//}
 #endif
diff --git a/back-ends/foma/cpp-version/iface.cc b/back-ends/foma/cpp-version/iface.cc
new file mode 100644
index 0000000..d657d39
--- /dev/null
+++ b/back-ends/foma/cpp-version/iface.cc
@@ -0,0 +1,1731 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2015 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "foma.h"
+#ifdef ORIGINAL
+#include "zlib.h"
+#else // #ifdef ORIGINAL
+  #ifdef ZLIB
+    #include "zlib.h"
+  #endif
+#endif // #ifdef ORIGINAL
+
+extern int g_show_flags;
+extern int g_obey_flags;
+extern int g_flag_is_epsilon;
+extern int g_print_space;
+extern int g_print_pairs;
+extern int g_minimal;
+extern int g_name_nets;
+extern int g_print_sigma;
+extern int g_quit_on_fail;
+extern int g_quote_special;
+extern int g_recursive_define;
+extern int g_sort_arcs;
+extern int g_verbose;
+extern int g_minimize_hopcroft;
+extern int g_list_limit;
+extern int g_list_random_limit;
+extern int g_compose_tristate;
+extern int g_med_limit ;
+extern int g_med_cutoff ;
+extern int g_lexc_align ;
+extern char *g_att_epsilon;
+
+extern struct defined_networks   *g_defines;
+extern struct defined_functions  *g_defines_f;
+
+#ifdef ORIGINAL
+extern int foma_net_print(struct fsm *net, gzFile outfile);
+#else // #ifdef ORIGINAL
+  #ifdef ZLIB
+    extern int foma_net_print(struct fsm *net, gzFile outfile);
+  #endif
+int snprintf(char *str, size_t size, const char *format, ...);
+#endif // #ifdef ORIGINAL
+
+static char *sigptr(struct sigma *sigma, int number);
+static int print_dot(struct fsm *net, char *filename);
+static int print_net(struct fsm *net, char *filename);
+static int print_sigma(struct sigma *sigma, FILE *out);
+static int view_net(struct fsm *net);
+
+#define FVAR_BOOL   1
+#define FVAR_INT    2
+#define FVAR_STRING 3
+
+#define LINE_LIMIT 8192
+
+struct g_v {
+    void *ptr;
+    char *name;
+    int  type;
+} global_vars[] = {
+    {&g_flag_is_epsilon,  "flag-is-epsilon",  FVAR_BOOL},
+    {&g_minimal,          "minimal",          FVAR_BOOL},
+    {&g_name_nets,        "name-nets",        FVAR_BOOL},
+    {&g_obey_flags,       "obey-flags",       FVAR_BOOL},
+    {&g_print_pairs,      "print-pairs",      FVAR_BOOL},
+    {&g_print_sigma,      "print-sigma",      FVAR_BOOL},
+    {&g_print_space,      "print-space",      FVAR_BOOL},
+    {&g_quit_on_fail,     "quit-on-fail",     FVAR_BOOL},
+    {&g_recursive_define, "recursive-define", FVAR_BOOL},
+    {&g_quote_special,    "quote-special",    FVAR_BOOL},
+    {&g_show_flags,       "show-flags",       FVAR_BOOL},
+    {&g_sort_arcs,        "sort-arcs",        FVAR_BOOL},
+    {&g_verbose,          "verbose",          FVAR_BOOL},
+    {&g_minimize_hopcroft,"hopcroft-min",     FVAR_BOOL},
+    {&g_compose_tristate, "compose-tristate", FVAR_BOOL},
+    {&g_med_limit,        "med-limit",        FVAR_INT},
+    {&g_med_cutoff,       "med-cutoff",       FVAR_INT},
+    {&g_lexc_align,       "lexc-align",       FVAR_BOOL},
+    {&g_att_epsilon,      "att-epsilon",      FVAR_STRING},
+    {NULL, NULL, 0}
+};
+
+char warranty[] = "\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License version 2 as published by\nthe Free Software Foundation.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\nYou should have received a copy of the GNU General [...]
+ 
+struct global_help {
+    char *name;
+    char *help;
+    char *longhelp;
+} global_help[] = {
+    {"regex <regex>", "read a regular expression","Enter a regular expression and add result to top of stack.\nShort form: re\nSee `help operator' for operators, or `help precedence' for operator precedence."},
+    {"ambiguous upper","returns the input words which have multiple paths in a transducer","Short form: ambiguous\n"},
+    {"apply up <string>","apply <string> up to the top network on stack","Short form: up <string>\n"},
+    {"apply down <string>","apply <string> down to the top network on stack","Short form: down <string>\n" },
+    {"apply med <string>","find approximate matches to string in top network by minimum edit distance","Short form: med <string>\n" },
+    {"apply up","enter apply up mode (Ctrl-D exits)","Short form: up\n"},
+    {"apply down","enter apply down mode (Ctrl-D exits)","Short form: down\n"},
+    {"apply med","enter apply med mode (Ctrl-D exits)","Short form: med\n"},
+    {"apropos <string>","search help for <string>",""},
+    {"clear stack","clears the stack",""},
+    {"close sigma","removes unknown symbols from FSM","" },
+    {"compact sigma","removes redundant symbols from FSM","" },
+    {"complete net","completes the FSM","" },
+    {"compose net","composes networks on stack",""},
+    {"concatenate","concatenates networks on stack","" },
+    {"crossproduct net","cross-product of top two FSMs on stack","See ×\n" },
+    {"define <name> <r.e.>","define a network","Example: \ndefine A x -> y;\n  and\nA = x -> y;\n\nare equivalent\n"},
+    {"define <fname>(<v1,..,vn>) <r.e.>","define function","Example: define Remove(X) [X -> 0].l;"},
+    {"determinize net","determinizes top FSM on stack",""},
+    {"echo <string>","echo a string",""},
+    {"eliminate flag <name>","eliminate flag <name> diacritics from the top network",""},
+    {"eliminate flags","eliminate all flag diacritics from the top network",""},
+    {"export cmatrix (filename)","export the confusion matrix as an AT&T transducer",""},
+    {"extract ambiguous","extracts the ambiguous paths of a transducer","Short form: examb"},
+    {"extract unambiguous","extracts the unambiguous paths of a transducer","Short form: exunamb"},
+    {"help license","prints license",""},
+    {"help warranty","prints warranty information",""},
+    {"ignore net","applies ignore to top two FSMs on stack","See /\n"},
+    {"intersect net","intersects FSMs on stack","See ∩ (or &)\n" },
+    {"invert net","inverts top FSM","See ⁻¹ (or .i)\n"},
+    {"label net","extracts all attested symbol pairs from FSM","See also: sigma net"},
+    {"letter machine","Converts top FSM to a letter machine","See also: _lm(L)"},
+    {"load stack <filename>","Loads networks and pushes them on the stack","Short form: load"},
+    {"load defined <filename>","Restores defined networks from file","Short form: loadd"},
+    {"lower-side net","takes lower projection of top FSM","See ₂ (or .l)\n"},
+    {"minimize net","minimizes top FSM","Minimization can be controlled through the variable minimal: when set to OFF FSMs are never minimized.\nAlso, hopcroft-min can be set to OFF in which case minimization is done by double reversal and determinization (aka Brzozowski's algorithm).  It is likely to be much slower.\n"},
+    {"name net <string>","names top FSM",""},
+    {"negate net","complements top FSM","See ¬\n" },
+    {"one-plus net","Kleene plus on top FSM","See +\n" },
+    {"pop stack","remove top FSM from stack","" },
+    {"print cmatrix","prints the confusion matrix associated with the top network in tabular format",""},
+    {"print defined","prints defined symbols and functions",""},
+    {"print dot (>filename)","prints top FSM in Graphviz dot format",""},
+    {"print lower-words","prints words on the lower side of top FSM",""},
+    {"print lower-words > filename","prints words on the lower side of top FSM to file",""},
+    {"print name","prints the name of the top FSM","" },
+    {"print net","prints all information about top FSM","Short form: net\n" },
+    {"print pairs","prints input-output pairs from top FSM","Short form: pairs\n"},
+    {"print pairs > filename","prints input-output pairs from top FSM to file","Short form: pairs\n"},
+    {"print random-lower","prints random words from lower side","Short form: random-lower\n" },
+    {"print random-upper","prints random words from upper side","Short form: random-upper" },
+    {"print random-words","prints random words from top FSM","Short form: random-words\n"},
+    {"print random-pairs","prints random input-output pairs from top FSM","Short form: random-pairs\n"},
+    {"print sigma","prints the alphabet of the top FSM","Short form: sigma\n"},
+    {"print size","prints size information about top FSM","Short form: size\n"},
+    {"print shortest-string","prints the shortest string of the top FSM","Short form: pss\n"},
+    {"print shortest-string-size","prints length of shortest string","Short form: psz\n"},
+    {"print upper-words","prints words on the upper side of top FSM","Short form: upper-words"},
+    {"print upper-words > filename","prints words on the upper side of top FSM to file","Short form:upper-words"},
+    {"print words","prints words of top FSM","Short form: words"},
+    {"print words > filename","prints words of top FSM to file","Short form: words"},
+    {"prune net","makes top network coaccessible",""},
+    {"push (defined) <name>","adds a defined FSM to top of stack",""},
+    {"quit","exit foma",""},
+    {"read att <filename>","read a file in AT&T FSM format and add to top of stack","Short form: ratt"},
+    {"read cmatrix <filename>","read a confusion matrix and associate it with the network on top of the stack",""},
+    {"read prolog <filename>","reads prolog format file",""},
+    {"read lexc <filename>","read and compile lexc format file",""},
+    {"read spaced-text <filename>","compile space-separated words/word-pairs separated by newlines into a FST",""},
+    {"read text <filename>","compile a list of words separated by newlines into an automaton",""},
+    {"reverse net","reverses top FSM","Short form: rev\nSee .r\n"},
+    {"rotate stack","rotates stack",""},
+    {"save defined <filename>","save all defined networks to binary file","Short form: saved" },
+    {"save stack <filename>","save stack to binary file","Short form: ss" },
+    {"set <variable> <ON|OFF>","sets a global variable (see show variables)","" },
+    {"show variables","prints all variable/value pairs",""},
+    {"shuffle net","asynchronous product on top two FSMs on stack","See ∥ (or <>)\n"},
+    {"sigma net","Extracts the alphabet and creates a FSM that accepts all single symbols in it","See also: label net"},
+    {"source <file>","read and compile script file",""},
+    {"sort net","sorts arcs topologically on top FSM",""},
+    {"sort in","sorts input arcs by sigma numbers on top FSM",""},
+    {"sort out","sorts output arcs by sigma number on top FSM",""},
+    {"substitute defined X for Y","substitutes defined network X at all arcs containing Y ",""},
+    {"substitute symbol X for Y","substitutes all occurrences of Y in an arc with X",""},
+    {"system <cmd>","execute a system command","" },
+    {"test unambiguous","test if top FST is unambiguous","Short form: tunam\n"},
+    {"test equivalent","test if the top two FSMs are equivalent","Short form: equ\nNote: equivalence is undecidable for transducers in the general case.  The result is reliable only for recognizers.\n"},
+    {"test functional","test if the top FST is functional (single-valued)","Short form: tfu\n"},
+    {"test identity","test if top FST represents identity relations only","Short form: tid\n"},
+    {"test lower-universal","test if lower side is Σ*","Short form: tlu\n"},
+    {"test upper-universal","test if upper side is Σ*","Short form: tuu\n"},
+    {"test non-null","test if top machine is not the empty language","Short form:tnn\n" },
+    {"test null","test if top machine is the empty language (∅)","Short form: tnu\n" },
+    {"test sequential","tests if top machine is sequential","Short form: tseq\n"},
+    {"test star-free","test if top FSM is star-free","Short form: tsf\n"},
+    {"turn stack","turns stack upside down","" },
+    {"twosided flag-diacritics","changes flags to always be identity pairs","Short form: tfd" },
+    {"undefine <name>","remove <name> from defined networks","See define\n"},
+    {"union net","union of top two FSMs","See ∪ (or |)\n"},
+    {"upper-side net","upper projection of top FSM","See ₁ (or .u)\n"},
+    {"view net","display top network (if supported)",""},
+    {"zero-plus net","Kleene star on top fsm","See *\n"},
+    {"variable compose-tristate","use the tristate composition algorithm","Default value: OFF\n"},
+    {"variable show-flags","show flag diacritics in `apply'","Default value: ON\n"},
+    {"variable obey-flags","obey flag diacritics in `apply'","Default value: ON\n"},
+    {"variable minimal","minimize resulting FSMs","Default value: ON\n"},
+    {"variable print-pairs","always print both sides when applying","Default value: OFF\n"},
+    {"variable print-space","print spaces between symbols","Default value: OFF\n"},
+    {"variable print-sigma","print the alphabet when printing network","Default value: ON\n"},
+    {"quit-on-fail","Abort operations when encountering errors","Default value: ON\n"},
+    {"variable recursive-define","Allow recursive definitions","Default value: OFF\n"},
+    {"variable verbose","Verbosity of interface","Default value: ON\n"},
+    {"variable hopcroft-min","ON = Hopcroft minimization, OFF = Brzozowski minimization","Default value: ON\n"},
+    {"variable med-limit","the limit on number of matches in apply med","Default value: 3\n"},
+    {"variable med-cutoff","the cost limit for terminating a search in apply med","Default value: 3\n"},
+    {"variable att-epsilon","the EPSILON symbol when reading/writing AT&T files","Default value: @0@\n"},
+    {"variable lexc-align","Forces X:0 X:X or 0:X alignment of lexicon entry symbols","Default value: OFF\n"},
+    {"write prolog (> filename)","writes top network to prolog format file/stdout","Short form: wpl"},
+    {"write att (> <filename>)","writes top network to AT&T format file/stdout","Short form: watt"},
+    {"re operator: (∀<var name>)(F)","universal quantification","Example: $.A is equivalent to:\n(∃x)(x ∈ A ∧ (∀y)(¬(y ∈ A ∧ ¬(x = y))))"},
+    {"re operator: (∃<var name>)(F)","existential quantification","Example: $.A is equivalent to:\n(∃x)(x ∈ A ∧ ¬(∃y)(y ∈ A ∧ ¬(x = y)))"},
+    {"logic re operator: ∈","`in' predicate for logical formulae",""},
+    {"logic re operator: S(t1,t2)","successor-of predicate for logical formulae",""},
+    {"logic re operator: ≤","less-than or equal-to","Refers to position of quantified substring\n" },
+    {"logic re operator: ≥","more-than or equal-to","Refers to position of quantified substring\n" },
+    {"logic re operator: ≺","precedes","Refers to position of quantified substring\n"},
+    {"logic re operator: ≻","follows","Refers to position of quantified substring\n"},
+    {"logic re operator: ∧","conjunction","Operationally equivalent to ∩\n"},
+    {"logic re operator: ∨","disjunction","Operationally equivalent to ∪\n"},
+    {"logic re operator: →","implication","A → B is equivalent to ¬A ∨ B "},
+    {"logic re operator: ↔","biconditional","A ↔ B is equivalent to (¬A ∨ B) ∧ (¬B ∨ A)"},
+    {"re operator: ∘ (or .o.) ","compose","A .o. B is the composition of transducers/recognizers A and B\nThe composition algorithm can be controlled with the variable\ncompose-tristate.  The default algorithm is a `bistate' composition that eliminates redundant paths but may fail to find the shortest path.\n"},
+    {"re operator: × (or .x.) ","cross-product","A × B (where A and B are recognizers, not transducers\nyields the cross-product of A and B.\n"},
+    {"re operator: .O. ","`lenient' composition","Lenient composition as defined in Karttunen(1998)  A .O. B = [A ∘ B] .P. B\n"},
+    {"re operator: ∥ (or <>) ","shuffle (asynchronous product)","A ∥ B yields the asynchronous (or shuffle) product of FSM A and B.\n" },
+    {"re operator: => ","context restriction, e.g. A => B _ C, D _ E","A => B _ C yields the language where every instance of a substring drawn from A is surrounded by B and C.  Multiple contexts can be specified if separated by commas, e.g.: A => B _ C, D _ E"},
+    {"re operator: ->, <-, <->, etc.","replacement operators","If LHS is a transducer, no RHS is needed in rule."},
+    {"re operator: @->, @>, etc.","directed replacement operators",""},
+    {"re operator: (->), (@->), etc. ","optional replacements","Optional replacement operators variants.  Note that the directional modes leftmost/rightmost/longest/shortest are not affected by optionality, i.e. only replacement is optional, not mode.  Hence A (@->) B is not in general equivalent to the parallel rule A @-> B, A -> ... "},
+    {"re operator: ||,\\/,\\\\,// ","replacement direction specifiers","Rewrite rules direction specifier meaning is:\nA -> B || C _ D (replace if C and D match on upper side)\nA -> B // C _ D (replace if C matches of lower side and D matches on upper side)\nA -> B \\\\ C _ D (replace if C matches on upper side and D matches on lower side)\nA -> B \\/ C _ D (replace if C and D match on lower side)\n"},
+    {"re operator: _ ","replacement or restriction context specifier",""},
+    {"re operator: ,,","parallel context replacement operator","Separates parallel rules, e.g.:\nA -> B , C @-> D || E _ F ,, G -> H \\/ I _ J\n"},
+    {"re operator: ,","parallel replacement operator","Separates rules and contexts. Example: A -> B, C <- D || E _ F"},
+    {"re operator: [.<r.e.>.]","single-epsilon control in replacement LHS, e.g. [..] -> x","If the LHS contains the empty string, as does [.a*.] -> x, the rule yields a transducer where the empty string is assumed to occur exactly once between each symbol."},
+    {"re operator: ...","markup replacement control (e.g. A -> B ... C || D _ E)","A -> B ... C yields a replacement transducer where the center A is left untouched and B and C inserted around A." },
+    {"re operator:  ","concatenation","Binary operator: A B\nConcatenation is performed implicitly according to its precedence level without overt specification\n"},
+    {"re operator: ∪ (or |) ","union","Binary operator: A|B"},
+    {"re operator: ∩ (or &) ","intersection","Binary operator: A&B" },
+    {"re operator: - ","set minus","Binary operator A-B"},
+    {"re operator: .P.","priority union (upper)","Binary operator A .P. B\nEquivalent to: A .P. B = A ∪ [¬[A₁] ∘ B]\n" },
+    {"re operator: .p.","priority union (lower)","Binary operator A .p. B\nEquivalent to: A .p. B = A ∪ [¬[A₂] ∘ B]" },
+    {"re operator: <","precedes","Binary operator A < B\nYields the language where no instance of A follows an instance of B."},
+    {"re operator: >","follows","Binary operator A > B\nYields the language where no instance of A precedes an instance of B."},
+    {"re operator: /","ignore","Binary operator A/B\nYield the language/transducer where arbitrary sequences of strings/mappings from B are interspersed in A.  For single-symbol languages B, A/B = A ∥ B*"},
+    {"re operator: ./.","ignore except at edges","Yields the language where arbitrary sequences from B are interspersed in A, except as the very first and very last symbol."},
+    {"re operator: \\\\\\","left quotient","Binary operator: A\\\\\\B\nInformally:  the set of suffixes one can add to A to get strings in B\n"},
+    {"re operator: ///","right quotient","Binary operator A///B\nInformally: the set of prefixes one can add to B to get a string in A\n"},
+    {"re operator: /\\/","interleaving quotient","Binary operator A/\\/B\nInformally: the set of strings you can interdigitate (non-continuously) to B to get strings in A\n"},
+    {"re operator: ¬ (or ~) ","complement","Unary operator ~A, equivalent to Σ* - A\n"},
+    {"re operator: $","contains a factor of","Unary operator $A\nEquivalent to: Σ* A Σ*\n"},
+    {"re operator: $.","contains exactly one factor of","Unary operator $.A\nYields the language that contains exactly one factor from A.\nExample: if A = [a b|b a], $.A contains strings ab, ba, abb, bba, but not abab, baba, aba, bab, etc.\n"},
+    {"re operator: $?","contains maximally one factor of","Unary operator: $?A, yields the language that contains zero or one factors from A. See also $.A."},
+    {"re operator: +","Kleene plus","Unary operator A+\n"},
+    {"re operator: *","Kleene star","Unary operator A*\n" },
+    {"re operator: ^n ^<n ^>n ^{m,n}","m, n-ary concatenations","A^n: A concatenated with itself exactly n times\nA^<n: A concatenated with itself less than n times\nA^>n: A concatenated with itself more than n times\nA^{m,n}: A concatenated with itself between m and n times\n"},
+    {"re operator: ₁ (or .1 or .u)","upper projection","Unary operator A.u\n"},
+    {"re operator: ₂ (or .2 or .l)","lower projection","Unary operator A.l\n"},
+    {"re operator: ⁻¹ (or .i)","inverse of transducer","Unary operator A.i\n"},
+    {"re operator: .f","eliminate all flags","Unary operator A.f: eliminates all flag diacritics in A"},
+    {"re operator: .r","reverse of FSM","Unary operator A.r\n"},
+    {"re operator: :","cross-product","Binary operator A:B, see also A × B\n"},
+    {"re operator: \\","term complement (\\x = [Σ-x])","Unary operator \\A\nSingle symbols not in A.  Equivalent to [Σ-A]\n"},
+    {"re operator: `","substitution/homomorphism","Ternary operator `[A,B,C] Replace instances of symbol B with symbol C in language A.  Also removes the substituted symbol from the alphabet.\n"},
+    {"re operator: { ... }","concatenate symbols","Single-symbol-concatenation\nExample: {abcd} is equivalent to a b c d\n"},
+    {"re operator: (A)","optionality","Equivalent to A | ε\nNote: parentheses inside logical formulas function as grouping, see ∀,∃\n"},
+    {"re operator: @\"filename\"","read saved network from file","Note: loads networks stored with e.g. \"save stack\" but if file contains more than one network, only the first one is used in the regular expression.  See also \"load stack\" and \"load defined\"\n"},
+    {"special symbol: Σ (or ?)","`any' symbol in r.e.",""},
+    {"special symbol: ε (or 0, [])","epsilon symbol in r.e.",""},
+    {"special symbol: ∅","the empty language symbol in r.e.",""},
+    {"special symbol: .#.","word boundary symbol in replacements, restrictions","Signifies both end and beginning of word/string\nExample: A => B _ .#. (allow A only between B and end-of-string)\nExample: A -> B || .#. _ C (replace A with B if it occurs in the beginning of a word and is followed by C)\n"},
+    {"operator precedence: ","see: `help precedence'","\\ `\n:\n+ * ^ ₁ ₂ ⁻¹ .f .r\n¬ $ $. $?\n(concatenation)\n> <\n∪ ∩ - .P. .p.\n=> -> (->) @-> etc.\n∥\n× ∘ .O.\nNote: compatibility variants (i.e. | = ∪ etc.) are not listed."},
+
+    {NULL,NULL,NULL}
+};
+
+void iface_help() {
+    struct global_help *gh;
+    int i, maxlen;
+
+    for (maxlen = 0, gh = global_help; gh->name != NULL; gh++) {
+        maxlen = maxlen < utf8strlen(gh->name) ? utf8strlen(gh->name) : maxlen;
+    }
+    for (gh = global_help; gh->name != NULL; gh++) {
+        printf("%s",gh->name);
+        for (i = maxlen - utf8strlen(gh->name); i>=0; i--) {
+            printf("%s"," ");
+        }
+        printf("%s\n",gh->help);
+    }
+}
+
+void iface_ambiguous_upper() {
+    if (iface_stack_check(1))
+        stack_add(fsm_extract_ambiguous_domain(stack_pop()));
+}
+
+void iface_apropos(char *s) {
+    struct global_help *gh;
+    int i, maxlen;
+
+    for (maxlen = 0, gh = global_help; gh->name != NULL; gh++) {
+        if (strstr(gh->name,s) != NULL || strstr(gh->help,s) != NULL) {
+            maxlen = maxlen < utf8strlen(gh->name) ? utf8strlen(gh->name) : maxlen;
+        }
+    }
+    for (gh = global_help; gh->name != NULL; gh++) {
+        if (strstr(gh->name,s) != NULL || strstr(gh->help,s) != NULL) {
+            printf("%s",gh->name);
+            for (i = maxlen - utf8strlen(gh->name); i>=0; i--) {
+                printf("%s"," ");
+            }
+            printf("%s\n",gh->help);
+        }
+    }
+}
+
+void iface_help_search(char *s) {
+    struct global_help *gh;
+    
+    for (gh = global_help; gh->name != NULL; gh++) {
+        if (strstr(gh->name,s) != NULL || strstr(gh->help,s) != NULL) {
+            printf("##\n");
+            printf("%-32.32s%s\n%s\n",gh->name,gh->help,gh->longhelp);
+        }
+    }
+}
+
+void iface_print_bool(int value) {
+    printf("%i (1 = TRUE, 0 = FALSE)\n",value);
+}
+
+void iface_warranty() {
+    printf("%s",warranty);
+}
+
+void iface_apply_set_params(struct apply_handle *h) {
+    apply_set_print_space(h, g_print_space);
+    apply_set_print_pairs(h, g_print_pairs);
+    apply_set_show_flags(h, g_show_flags);
+    apply_set_obey_flags(h, g_obey_flags);
+}
+
+void iface_apply_med(char *word) {
+    char *result;
+    struct apply_med_handle *amedh;
+    if (!iface_stack_check(1)) {
+        return;
+    }
+    amedh = stack_get_med_ah();
+
+    apply_med_set_heap_max(amedh,4194304+1);
+    apply_med_set_med_limit(amedh,g_med_limit);
+    apply_med_set_med_cutoff(amedh,g_med_cutoff);
+
+    result = apply_med(amedh, word);
+    if (result == NULL) {
+        printf("???\n");
+        return;
+    } else {
+        printf("%s\n",result);
+	printf("%s\n", apply_med_get_instring(amedh));
+	printf("Cost[f]: %i\n\n", apply_med_get_cost(amedh));
+    }
+    while ((result = apply_med(amedh,NULL)) != NULL) {
+        printf("%s\n",result);
+	printf("%s\n", apply_med_get_instring(amedh));
+	printf("Cost[f]: %i\n\n", apply_med_get_cost(amedh));
+    }
+}
+
+int iface_apply_file(char *infilename, char *outfilename, int direction) {
+    char *result, inword[LINE_LIMIT];
+    struct apply_handle *ah;
+    FILE *OUTFILE, *INFILE;
+
+    if (direction != AP_D && direction != AP_U) {
+        perror("Invalid direction in iface_apply_file().\n");
+        return 1;
+    }
+    if (!iface_stack_check(1)) { return 0; }
+    INFILE = fopen(infilename, "r");
+    if (INFILE == NULL) {
+	fprintf(stderr, "%s: ", infilename);
+        perror("Error opening file");
+        return 1;
+    }
+    
+    if (outfilename == NULL) {
+        OUTFILE = stdout;
+    } else {
+        OUTFILE = fopen(outfilename, "w");
+        printf("Writing output to file %s.\n", outfilename);
+        if (OUTFILE == NULL) {
+	    fprintf(stderr, "%s: ", outfilename);
+            perror("Error opening output file.");
+            return 1;
+        }
+    }
+    ah = stack_get_ah();
+    iface_apply_set_params(ah);
+    while ((fgets(inword,LINE_LIMIT,INFILE)) != NULL) {
+        if (inword[strlen(inword)-1] == '\n') {
+            inword[strlen(inword)-1] = '\0';
+        }
+
+        fprintf(OUTFILE,"\n%s\n", inword);
+        if (direction == AP_D)
+            result = apply_down(ah,inword);
+        else
+            result = apply_up(ah,inword);
+        
+        if (result == NULL) {
+            fprintf(OUTFILE,"???\n");
+            continue;
+        } else {
+            fprintf(OUTFILE,"%s\n",result);
+        }
+        for (;;) {
+            if (direction == AP_D)
+                result = apply_down(ah,NULL);
+            if (direction == AP_U)
+                result = apply_up(ah,NULL);
+            if (result == NULL)
+                break;
+            fprintf(OUTFILE,"%s\n", result);
+        }
+    }
+    if (outfilename != NULL)
+        fclose(OUTFILE);
+    return 0;
+}
+
+void iface_apply_down(char *word) {
+    int i;
+    char *result;
+    struct apply_handle *ah;
+    if (!iface_stack_check(1)) {
+        return;
+    }
+    ah = stack_get_ah();
+    iface_apply_set_params(ah);
+    result = apply_down(ah, word);
+    if (result == NULL) {
+        printf("???\n");
+        return;
+    } else {
+        printf("%s\n",result);
+    }
+    for (i = g_list_limit; i > 0; i--) {
+        result = apply_down(ah, NULL);
+        if (result == NULL)
+            break;
+        printf("%s\n",result);
+    }
+}
+
+void iface_apply_up(char *word) {
+    int i;
+    char *result;
+    struct apply_handle *ah;
+    if (!iface_stack_check(1)) {
+        return;
+    }
+    ah = stack_get_ah();
+    
+    iface_apply_set_params(ah);
+    result = apply_up(ah, word);
+
+    if (result == NULL) {
+        printf("???\n");
+        return;
+    } else {
+        printf("%s\n",result);
+    }
+    for (i = g_list_limit; i > 0; i--) {
+        result = apply_up(ah, NULL);
+        if (result == NULL)
+            break;
+        printf("%s\n",result);
+    }
+}
+
+void iface_close() {
+    if (iface_stack_check(1)) {
+      stack_add(fsm_topsort(fsm_minimize(fsm_close_sigma(stack_pop(),0))));
+    }
+}
+
+void iface_compact() {
+    if (iface_stack_check(1)) {
+        fsm_compact(stack_find_top()->fsm);
+	sigma_sort(stack_find_top()->fsm);
+        stack_add(fsm_topsort(fsm_minimize(stack_pop())));
+    }
+}
+
+void iface_complete() {
+    if (iface_stack_check(1))
+        stack_add(fsm_complete(stack_pop()));
+}
+
+
+void iface_compose() {
+    struct fsm *one, *two;
+    if (iface_stack_check(2)) {
+        while (stack_size()>1) {
+	    one = stack_pop();
+	    two = stack_pop();
+	    stack_add(fsm_topsort(fsm_minimize(fsm_compose(one,two))));
+	}
+    }
+}
+
+void iface_conc() {
+    struct fsm *one, *two;
+    if (iface_stack_check(2)) {
+        while (stack_size()>1) {
+	    printf("dd");
+	    one = stack_pop();
+	    two = stack_pop();
+	    stack_add(fsm_topsort(fsm_minimize(fsm_concat(one,two))));
+	}
+    }
+}
+
+void iface_crossproduct() {
+    struct fsm *one, *two;
+    if (iface_stack_check(2)) {
+	one = stack_pop();
+	two = stack_pop();
+        stack_add(fsm_topsort(fsm_minimize(fsm_cross_product(one,two))));
+    }
+}
+void iface_determinize() {
+    if (iface_stack_check(1))
+        stack_add(fsm_determinize(stack_pop()));
+}
+
+void iface_eliminate_flags() {
+    if (iface_stack_check(1))
+        stack_add(flag_eliminate(stack_pop(), NULL));
+}
+
+void iface_extract_ambiguous() {
+    if (iface_stack_check(1))
+        stack_add(fsm_extract_ambiguous(stack_pop()));
+}
+
+void iface_extract_unambiguous() {
+    if (iface_stack_check(1))
+        stack_add(fsm_extract_unambiguous(stack_pop()));
+}
+
+int iface_extract_number(char *s) {
+    int i;
+    for (i=0; *(s+i) != '\0' && ((unsigned char) *(s+i) < '0' || (unsigned char) *(s+i) > '9'); i++) { }
+    return(atoi(s+i));
+}
+
+void iface_eliminate_flag(char *name) {
+    if (iface_stack_check(1))
+        stack_add(flag_eliminate(stack_pop(), name));
+}
+
+void iface_factorize() {
+    if (iface_stack_check(1))
+        stack_add(fsm_bimachine(stack_pop()));
+}
+
+void iface_sequentialize() {
+    if (iface_stack_check(1))
+        stack_add(fsm_sequentialize(stack_pop()));
+}
+
+void iface_ignore() {
+    struct fsm *one, *two;
+    if (iface_stack_check(2)) {
+	one = stack_pop();
+	two = stack_pop();
+        stack_add(fsm_topsort(fsm_minimize(fsm_ignore(one,two,OP_IGNORE_ALL))));
+    }
+}
+
+void iface_intersect() {
+    if (iface_stack_check(2)) {
+        while (stack_size()>1)
+            stack_add(fsm_topsort(fsm_minimize(fsm_intersect(stack_pop(),stack_pop()))));
+    }
+}
+
+void iface_invert() {
+    if (iface_stack_check(1))
+        stack_add(fsm_invert(stack_pop()));
+}
+
+void iface_label_net() {
+    if (iface_stack_check(1))
+        stack_add(fsm_sigma_pairs_net(stack_pop()));
+}
+
+void iface_letter_machine() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_letter_machine(stack_pop()))));
+}
+
+void iface_load_defined(char *filename) {
+    load_defined(g_defines, filename);
+}
+
+void iface_load_stack(char *filename) {
+    struct fsm *net;
+    fsm_read_binary_handle fsrh;
+
+    if ((fsrh = fsm_read_binary_file_multiple_init(filename)) == NULL) {
+	fprintf(stderr, "%s: ", filename);
+        perror("File error");
+        return;
+    }
+    while ((net = fsm_read_binary_file_multiple(fsrh)) != NULL)
+        stack_add(net);
+    return;
+}
+
+void iface_lower_side() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_lower(stack_pop()))));
+}
+
+void iface_minimize() {
+    int store_minimal_var;
+    if (iface_stack_check(1)) {
+        store_minimal_var = g_minimal;
+        g_minimal = 1;
+        stack_add(fsm_topsort(fsm_minimize(stack_pop())));
+        g_minimal = store_minimal_var;
+    }
+}
+
+void iface_one_plus() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_kleene_plus(stack_pop()))));
+}
+
+void iface_pop() {
+    struct fsm *net;
+    if (stack_size() < 1)
+        printf("Stack is empty.\n");
+    else {
+        net = stack_pop();
+	fsm_destroy(net);
+    }
+}
+
+void iface_lower_words(int limit) {
+    char *result;
+    struct apply_handle *ah;
+    int i;
+    if (!iface_stack_check(1)) {
+        return;
+    }
+    limit = (limit == -1) ? g_list_limit : limit;
+    if (iface_stack_check(1)) {
+      ah = stack_get_ah();
+      iface_apply_set_params(ah);
+        for (i = limit; i > 0; i--) {
+            result = apply_lower_words(ah);
+            if (result == NULL)
+                break;
+            printf("%s\n",result);
+        }
+	apply_reset_enumerator(ah);
+    }
+}
+
+void iface_name_net(char *name) {
+    if (iface_stack_check(1)) {
+        strncpy(stack_find_top()->fsm->name, name, 40);
+        iface_print_name();
+    }
+}
+void iface_negate() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_complement(stack_pop()))));
+}
+
+void iface_print_dot(char *filename) {
+    if (iface_stack_check(1)) {
+        if (filename != NULL)
+            printf("Writing dot file to %s.\n",filename);
+        print_dot(stack_find_top()->fsm, filename);
+    }
+}
+
+void iface_print_net(char *netname, char *filename) {
+    struct fsm *net;
+    if (netname != NULL) {
+        if ((net = find_defined(g_defines, netname)) == NULL) {
+            printf("No defined network %s.\n", netname);
+            return;
+        }
+        print_net(net, filename);
+    } else {
+        if (iface_stack_check(1))
+            print_net(stack_find_top()->fsm, filename);
+    }
+}
+
+void iface_print_cmatrix_att(char *filename) {
+    FILE *outfile;
+    if (iface_stack_check(1)) {
+        if (stack_find_top()->fsm->medlookup == NULL || stack_find_top()->fsm->medlookup->confusion_matrix == NULL) {
+            printf("No confusion matrix defined.\n");
+        } else {
+            if (filename == NULL) {
+                outfile = stdout;
+            } else {
+                outfile = fopen(filename,"w");
+                printf("Writing confusion matrix to file '%s'.\n", filename);
+            }
+            cmatrix_print_att(stack_find_top()->fsm, outfile);
+        }
+    }
+}
+
+void iface_print_cmatrix() {
+    if (iface_stack_check(1)) {
+        if (stack_find_top()->fsm->medlookup == NULL || stack_find_top()->fsm->medlookup->confusion_matrix == NULL) {
+            printf("No confusion matrix defined.\n");
+        } else {
+            cmatrix_print(stack_find_top()->fsm);
+        }
+    }
+}
+
+void iface_print_defined() {
+    struct defined_networks  *defined;
+    struct defined_functions *defined_f;
+    if (g_defines == NULL) {
+        printf("No defined symbols.\n");
+    }
+    for (defined = g_defines; defined != NULL; defined = defined->next) {
+	if (defined->name != NULL) {
+	    printf("%s\t",defined->name);
+	    print_stats(defined->net);
+	}
+    }
+    for (defined_f = g_defines_f; defined_f != NULL; defined_f = defined_f->next) {
+	if (defined_f->name != NULL) {
+		printf("%s@%i)\t",defined_f->name,defined_f->numargs);
+		printf("%s\n",defined_f->regex);
+	}
+    }
+}
+
+void iface_print_name() {
+    if (iface_stack_check(1))
+        printf("%s\n",stack_find_top()->fsm->name);
+}
+
+void iface_quit() {
+    struct fsm *net;
+    remove_defined(g_defines, NULL);
+    while (!(stack_isempty())) {
+        net = stack_pop();
+        fsm_destroy(net);
+    }
+    exit(0);
+}
+
+void iface_random_lower(int limit) {
+    iface_apply_random(&apply_random_lower, limit);
+}
+
+void iface_random_upper(int limit) {
+    iface_apply_random(&apply_random_upper, limit);
+}
+
+void iface_random_words(int limit) {
+    iface_apply_random(&apply_random_words, limit);
+}
+
+void iface_apply_random(char *(*applyer)(), int limit) {
+    char *result;
+    struct apply_handle *ah;
+    int i;
+    struct apply_results {
+	char *string;
+	int count;
+    } *results, *tempresults;
+
+    limit = (limit == -1) ? g_list_random_limit : limit;
+    if (iface_stack_check(1)) {
+	results = xxcalloc(limit, sizeof(struct apply_results));
+	ah = stack_get_ah();
+	iface_apply_set_params(ah);
+        for (i = limit; i > 0; i--) {
+	    result = NULL;
+            result = applyer(ah);
+            if (result != NULL) {
+		for (tempresults = results; tempresults - results < limit; tempresults++) {
+		    if (tempresults->string == NULL) {
+			tempresults->string = xxstrdup(result);
+			tempresults->count = 1;
+			break;
+		    }
+		    else if (strcmp(tempresults->string, result) == 0) {
+			tempresults->count++;
+			break;
+		    }
+		}
+	    }
+        }
+	for (tempresults = results; tempresults - results < limit; tempresults++) {
+	    if (tempresults->string != NULL) {
+		printf("[%i] %s\n", tempresults->count, tempresults->string);
+		xxfree(tempresults->string);
+	    }
+	}
+	xxfree(results);
+	apply_reset_enumerator(ah);
+    }
+}
+
+void iface_print_sigma() {
+    if (iface_stack_check(1))
+        print_sigma(stack_find_top()->fsm->sigma,stdout);
+}
+void iface_print_stats() {
+    if (iface_stack_check(1))
+        print_stats(stack_find_top()->fsm);
+}
+
+void iface_print_shortest_string() {
+    /* L -  ?+  [[L .o. [?:"@TMP@"]*].l .o. "@TMP@":?*].l; */
+    struct fsm *Result, *ResultU, *ResultL, *one, *onel, *oneu;
+    struct apply_handle *ah;
+    char *word;
+    if (iface_stack_check(1)) {
+        one = fsm_copy(stack_find_top()->fsm);
+        /* L -  ?+  [[L .o. [?:"@TMP@"]*].l .o. "@TMP@":?*].l; */
+        if (stack_find_top()->fsm->arity == 1) {
+            Result = fsm_minimize(fsm_minus(fsm_copy(one),fsm_concat(fsm_kleene_plus(fsm_identity()),fsm_lower(fsm_compose(fsm_lower(fsm_compose(fsm_copy(one),fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("@TMP@"))))),fsm_kleene_star(fsm_cross_product(fsm_symbol("@TMP@"),fsm_identity())))))));
+            ah = apply_init(Result);
+            word = apply_words(ah);
+            if (word != NULL) printf("%s\n",word);
+	    apply_clear(ah);
+        } else {
+            onel = fsm_lower(fsm_copy(one));
+            oneu = fsm_upper(one);
+            ResultU = fsm_minimize(fsm_minus(fsm_copy(oneu),fsm_concat(fsm_kleene_plus(fsm_identity()),fsm_lower(fsm_compose(fsm_lower(fsm_compose(fsm_copy(oneu),fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("@TMP@"))))),fsm_kleene_star(fsm_cross_product(fsm_symbol("@TMP@"),fsm_identity())))))));
+            ResultL = fsm_minimize(fsm_minus(fsm_copy(onel),fsm_concat(fsm_kleene_plus(fsm_identity()),fsm_lower(fsm_compose(fsm_lower(fsm_compose(fsm_copy(onel),fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("@TMP@"))))),fsm_kleene_star(fsm_cross_product(fsm_symbol("@TMP@"),fsm_identity())))))));
+            ah = apply_init(ResultU);
+            word = apply_words(ah);
+            if (word == NULL) word = "";
+            printf("Upper: %s\n",word);
+	    apply_clear(ah);
+            ah = apply_init(ResultL);
+            word = apply_words(ah);
+            if (word == NULL) word = "";
+            printf("Lower: %s\n",word);
+	    apply_clear(ah);
+        }
+    }
+}
+
+void iface_print_shortest_string_size() {
+    struct fsm *Result, *ResultU, *ResultL, *one, *onel, *oneu;
+    if (iface_stack_check(1)) {
+        one = fsm_copy(stack_find_top()->fsm);
+        /* [L .o. [?:a]*].l; */
+        if (stack_find_top()->fsm->arity == 1) {
+            Result = fsm_minimize(fsm_lower(fsm_compose(one,fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("a"))))));
+            printf("Shortest acyclic path length: %i\n",Result->statecount-1);
+
+        } else {
+            onel = fsm_lower(fsm_copy(one));
+            oneu = fsm_upper(one);
+            ResultU = fsm_minimize(fsm_lower(fsm_compose(oneu,fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("a"))))));
+            ResultL = fsm_minimize(fsm_lower(fsm_compose(onel,fsm_kleene_star(fsm_cross_product(fsm_identity(),fsm_symbol("a"))))));
+            printf("Shortest acyclic upper path length: %i\n",(ResultU->statecount)-1);
+            printf("Shortest acyclic lower path length: %i\n",(ResultL->statecount)-1);
+        }
+    }
+}
+
+int iface_read_att(char *filename) {
+    struct fsm *tempnet;
+    printf("Reading AT&T file: %s\n",filename);
+    tempnet = read_att(filename);
+    if (tempnet == NULL) {
+	fprintf(stderr, "%s: ", filename);
+        perror("Error opening file");
+        return 1;
+    } else {
+        stack_add(tempnet);
+        return 0;
+    }
+}
+
+int iface_read_prolog(char *filename) {
+    struct fsm *tempnet;
+    printf("Reading prolog: %s\n",filename);
+    tempnet = fsm_read_prolog(filename);
+    if (tempnet == NULL) {
+	fprintf(stderr, "%s: ", filename);
+        perror ("Error opening file");
+        return 1;
+    } else {
+        stack_add(tempnet);
+        return 0;
+    }
+}
+
+int iface_read_spaced_text(char *filename) {
+    struct fsm *net;
+    net = fsm_read_spaced_text_file(filename);
+    if (net == NULL) {
+	fprintf(stderr, "%s: ", filename);
+	perror("File error");
+	return 1;
+    }
+    stack_add(fsm_topsort(fsm_minimize(net)));
+    return 0;
+}
+
+int iface_read_text(char *filename) {
+    struct fsm *net;
+    net = fsm_read_text_file(filename);
+    if (net == NULL) {
+	fprintf(stderr, "%s: ", filename);
+	perror("File error");
+	return 1;
+    }
+    stack_add(fsm_topsort(fsm_minimize(net)));
+    return 0;
+}
+
+int iface_stack_check (int size) {
+    if (stack_size() < size) {
+        printf("Not enough networks on stack. Operation requires at least %i.\n",size);
+        return 0;
+    }
+    return 1;
+}
+
+void iface_substitute_symbol (char *original, char *substitute) {
+    if (iface_stack_check(1)) {
+        dequote_string(original);
+        dequote_string(substitute);
+        stack_add(fsm_topsort(fsm_minimize(fsm_substitute_symbol(stack_pop(), original, substitute))));
+        printf("Substituted '%s' for '%s'.\n", substitute, original);
+    }
+}
+
+void iface_substitute_defined (char *original, char *substitute) {
+    struct fsm *subnet;
+    struct fsm *newnet;
+    if (iface_stack_check(1)) {
+        dequote_string(original);
+        dequote_string(substitute);
+	if ((subnet = find_defined(g_defines, substitute)) == NULL) {
+	    printf("No defined network '%s'.\n",substitute);
+	} else {
+	    if (fsm_symbol_occurs(stack_find_top()->fsm, original, M_UPPER + M_LOWER) == 0) {
+		printf("Symbol '%s' does not occur.\n", original);
+	    } else {
+		newnet = fsm_substitute_label(stack_find_top()->fsm, original, subnet);
+		stack_pop();
+		printf("Substituted network '%s' for '%s'.\n", substitute, original);
+		stack_add(fsm_topsort(fsm_minimize(newnet)));
+	    }
+	}
+    }
+}
+
+void iface_upper_words(int limit) {
+    char *result;
+    struct apply_handle *ah;
+    int i;
+    limit = (limit == -1) ? g_list_limit : limit;
+    if (iface_stack_check(1)) {
+        ah = stack_get_ah();
+	iface_apply_set_params(ah);
+        for (i = limit; i > 0; i--) {
+            result = apply_upper_words(ah);
+            if (result == NULL)
+                break;
+            printf("%s\n",result);
+        }
+	apply_reset_enumerator(ah);
+    }
+}
+
+void iface_prune() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_coaccessible(stack_pop())));
+}
+void iface_reverse() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_determinize(fsm_reverse((stack_pop())))));
+}
+void iface_rotate() {
+    if (iface_stack_check(1))
+        stack_rotate();
+}
+void iface_save_defined(char *filename) {
+    save_defined(g_defines, filename);
+}
+
+#if defined(ORIGINAL) || defined(ZLIB)
+void iface_save_stack(char *filename) {
+    gzFile outfile;
+    struct stack_entry *stack_ptr;
+
+    if (iface_stack_check(1)) {
+      if ((outfile = gzopen(filename, "wb")) == NULL) {
+            printf("Error opening file %s for writing.\n", filename);
+            return;
+        }
+        printf("Writing to file %s.\n", filename);
+        for (stack_ptr = stack_find_bottom(); stack_ptr->next != NULL; stack_ptr = stack_ptr->next) {
+          foma_net_print(stack_ptr->fsm, outfile);
+        }
+        gzclose(outfile);
+        return;
+    }
+}
+#else
+void iface_save_stack(char *filename) {
+  fprintf(stderr, "IFACE_C_ERROR\n"); exit(1); }
+#endif
+
+void iface_show_variables() {
+    int i;
+    for (i=0; global_vars[i].name != NULL; i++) {
+        if (global_vars[i].type == FVAR_BOOL) {
+            printf("%-17.17s: %s\n",global_vars[i].name, *((int *)(global_vars[i].ptr)) == 1 ? "ON" : "OFF");
+        }
+        if (global_vars[i].type == FVAR_INT) {
+            printf("%-17.17s: %i\n",global_vars[i].name, *((int *)(global_vars[i].ptr)));
+        }
+        if (global_vars[i].type == FVAR_STRING) {
+            printf("%-17.17s: %s\n",global_vars[i].name, *((char **)(global_vars[i].ptr)) );
+        }
+    }
+}
+void iface_show_variable(char *name) {
+    int i;
+    for (i=0; global_vars[i].name != NULL; i++) {
+        if (strncmp(name,global_vars[i].name,8) == 0) {
+	    printf("%s = %s\n",global_vars[i].name, *((int *)(global_vars[i].ptr)) == 1 ? "ON" : "OFF");
+            return;
+        }
+    }
+    printf("*There is no global variable '%s'.\n",name);
+}
+
+void iface_set_variable(char *name, char *value) {
+    int i,j;
+    char *endptr;
+    for (i=0; global_vars[i].name != NULL; i++) {
+        if (strncmp(name,global_vars[i].name,8) == 0) {
+            if (global_vars[i].type == FVAR_BOOL) {
+                if ((strcmp(value,"ON") == 0) || (strcmp(value, "1") == 0)) {
+                    j = 1;
+                } else if ((strcmp(value,"OFF") == 0) || (strcmp(value, "0") == 0)) {
+                    j = 0;
+                } else {
+                    printf("Invalid value '%s' for variable '%s'\n",value, global_vars[i].name);
+                    return;
+                }
+                *((int *)(global_vars[i].ptr)) = j;
+                printf("variable %s = %s\n",global_vars[i].name, *((int *)(global_vars[i].ptr)) == 1 ? "ON" : "OFF");
+                return;
+            }
+            if (global_vars[i].type == FVAR_STRING) {
+                *((char **)(global_vars[i].ptr)) = xxstrdup(value);
+                printf("variable %s = %s\n",global_vars[i].name, value);
+                return;
+            }
+            if (global_vars[i].type == FVAR_INT) {
+                errno = 0;
+                j = strtol(value, &endptr, 10);
+                if ((errno != 0 || endptr == value) || j < 0) {
+                    printf("invalid value %s for variable %s\n", value, global_vars[i].name);
+                    return;
+                } else {
+                    printf("variable %s = %i\n", global_vars[i].name, j);
+                    *((int *)(global_vars[i].ptr)) = j;
+                    return;
+                }
+            }
+        }
+    }
+    printf("*There is no global variable '%s'.\n",name);
+}
+
+void iface_shuffle() {
+    if (iface_stack_check(2))
+        while (stack_size()>1)
+            stack_add(fsm_minimize(fsm_shuffle(stack_pop(),stack_pop())));
+}
+
+void iface_sigma_net() {
+    if (iface_stack_check(1))
+        stack_add(fsm_sigma_net(stack_pop()));
+}
+
+void iface_sort_input() {
+    if (iface_stack_check(1)) {
+        fsm_sort_arcs(stack_find_top()->fsm,1);
+    }
+}
+
+void iface_sort_output() {
+    if (iface_stack_check(1)) {
+        fsm_sort_arcs(stack_find_top()->fsm,2);
+    }
+}
+
+void iface_sort() {
+    if (iface_stack_check(1)) {
+        sigma_sort(stack_find_top()->fsm);
+        stack_add(fsm_topsort(stack_pop()));
+    }
+}
+
+
+void iface_test_equivalent() {
+  struct fsm *one, *two;
+    if (iface_stack_check(2)) {
+        one = fsm_copy(stack_find_top()->fsm);
+        two = fsm_copy(stack_find_second()->fsm);
+	fsm_count(one);
+	fsm_count(two);
+	
+	//if (one->arccount != two->arccount || one->statecount != two->statecount || one->finalcount != two->finalcount) {
+	//iface_print_bool(0);
+	    //} else {
+	    iface_print_bool(fsm_equivalent(one, two));
+	    //iface_print_bool(fsm_isempty(fsm_union(fsm_minus(fsm_copy(one),fsm_copy(two)),fsm_minus(fsm_copy(two),fsm_copy(one)))));
+	    //}
+    }
+}
+
+void iface_test_functional() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isfunctional(stack_find_top()->fsm));
+}
+
+void iface_test_identity() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isidentity(stack_find_top()->fsm));
+}
+
+void iface_test_nonnull() {
+    if (iface_stack_check(1))
+        iface_print_bool(!fsm_isempty(fsm_copy(stack_find_top()->fsm)));
+}
+
+void iface_test_null() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isempty(fsm_copy(stack_find_top()->fsm)));
+}
+
+void iface_test_unambiguous() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isunambiguous(stack_find_top()->fsm));
+}
+
+void iface_test_lower_universal() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isempty(fsm_complement(fsm_lower(fsm_copy(stack_find_top()->fsm)))));
+}
+
+void iface_test_sequential() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_issequential(stack_find_top()->fsm));
+}
+
+void iface_test_upper_universal() {
+    if (iface_stack_check(1))
+        iface_print_bool(fsm_isempty(fsm_complement(fsm_upper(fsm_copy(stack_find_top()->fsm)))));
+}
+
+void iface_turn() {
+    if (iface_stack_check(1))
+        stack_rotate();
+}
+
+void iface_twosided_flags() {
+  if (iface_stack_check(1)) {
+    stack_add(flag_twosided(stack_pop()));
+  }
+}
+
+void iface_union() {
+    if (iface_stack_check(2))
+        while (stack_size()>1)
+            stack_add(fsm_minimize(fsm_union(stack_pop(),stack_pop())));
+}
+void iface_upper_side() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_upper(stack_pop()))));
+}
+
+void iface_view() {
+    if (iface_stack_check(1))
+        view_net(stack_find_top()->fsm);
+}
+
+void iface_words_file(char *filename, int type) {
+    /* type 0 (words), 1 (upper-words), 2 (lower-words) */
+    FILE *outfile;
+    char *result;
+    static char *(*applyer)() = &apply_words;
+    struct apply_handle *ah;
+
+    if (type == 1) {
+	applyer = &apply_upper_words;
+    }
+    if (type == 2) {
+	applyer = &apply_lower_words;
+    }
+    if (iface_stack_check(1)) {
+	if (stack_find_top()->fsm->pathcount == PATHCOUNT_CYCLIC) {
+	    printf("FSM is cyclic: can't write all words to file.\n");
+	    return;
+	}
+	printf("Writing to %s.\n",filename);
+	if ((outfile = fopen(filename, "w")) == NULL) {
+	    perror("Error opening file");
+	    return;
+	}
+        ah = stack_get_ah();
+	iface_apply_set_params(ah);
+        for (;;) {
+            result = applyer(ah);
+            if (result == NULL)
+                break;
+            fprintf(outfile,"%s\n",result);
+        }
+        apply_reset_enumerator(ah);
+	fclose(outfile);
+    }
+}
+
+void iface_words(int limit) {
+    char *result;
+    struct apply_handle *ah;
+    int i;
+    limit = (limit == -1) ? g_list_limit : limit;
+    if (iface_stack_check(1)) {
+        ah = stack_get_ah();
+	iface_apply_set_params(ah);
+        for (i = limit; i > 0; i--) {
+            result = apply_words(ah);
+            if (result == NULL)
+                break;
+            printf("%s\n",result);
+        }
+        apply_reset_enumerator(ah);
+    }
+}
+
+/* Splits string of upper:lower pairs with space separator into two strings */
+/* e.g. a:b c:d e 0:g => ace,bdeg  */
+
+void iface_split_string(char *result, char *string) {
+    int i;
+    char space = '\001', epsilon = '\002', separator = '\003';
+    /* Simulate: SEPARATOR \SPACE+ @-> 0 .o. SPACE|SEPARATOR|EPSILON -> 0 */
+    /*           to extract only upper side of string                     */
+    for (i = 0 ; ; ) {
+    zero:
+	if (result[i] == '\0') {
+	    break;
+	} else if (result[i] == space || result[i] == epsilon) {
+	    i++;
+	    goto zero;
+	} else if (result[i] == separator) {
+	    i++;
+	    goto one;
+	} else {
+	    strncat(string, result+i, 1);
+	    i++;
+	    goto zero;
+	}
+    one:
+	if (result[i] == '\0') {
+	    break;
+	} else if (result[i] == space) {
+	    i++;
+	    goto zero;
+	} else {
+	    i++;
+	    goto one;
+	}
+    }
+}
+
+void iface_split_result(char *result, char **upper, char **lower) {
+    *upper = calloc(strlen(result), sizeof(char));
+    *lower = calloc(strlen(result), sizeof(char));
+    /* Split string into upper by filtering input side */
+    /* and lower by the same filter, but reversed      */
+    iface_split_string(result, *upper);
+    xstrrev(result);
+    iface_split_string(result, *lower);
+    xstrrev(*lower);
+    xstrrev(result);
+}
+
+
+void iface_pairs_call(int limit, int random) {
+    char *result, *upper, *lower;
+    struct apply_handle *ah;
+    int i;
+    limit = (limit == -1) ? g_list_limit : limit;
+    if (iface_stack_check(1)) {
+        ah = stack_get_ah();
+	apply_set_show_flags(ah, g_show_flags);
+	apply_set_obey_flags(ah, g_obey_flags);
+	apply_set_space_symbol(ah, "\001");
+	apply_set_epsilon(ah, "\002");
+	apply_set_separator(ah, "\003");
+        for (i = limit; i > 0; i--) {
+	    if (random == 1)
+		result = apply_random_words(ah);
+	    else
+		result = apply_words(ah);
+            if (result == NULL)
+                break;
+	    iface_split_result(result, &upper, &lower);
+            printf("%s\t%s\n",upper, lower);
+	    xxfree(upper);
+	    xxfree(lower);
+        }
+	apply_set_space_symbol(ah, " ");
+	apply_set_epsilon(ah, "0");
+	apply_set_separator(ah, ":");
+        apply_reset_enumerator(ah);
+    }
+}
+
+void iface_random_pairs(int limit) {
+    iface_pairs_call(limit, 1);
+}
+
+void iface_pairs(int limit) {
+    iface_pairs_call(limit, 0);
+}
+
+void iface_pairs_file(char *filename) {
+    FILE *outfile;
+    char *result, *upper, *lower;
+    struct apply_handle *ah;
+    if (iface_stack_check(1)) {
+	if (stack_find_top()->fsm->pathcount == PATHCOUNT_CYCLIC) {
+	    printf("FSM is cyclic: can't write all pairs to file.\n");
+	    return;
+	}
+	printf("Writing to %s.\n",filename);
+	if ((outfile = fopen(filename, "w")) == NULL) {
+	    perror("Error opening file");
+	    return;
+	}
+	ah = stack_get_ah();
+	apply_set_show_flags(ah, g_show_flags);
+	apply_set_obey_flags(ah, g_obey_flags);
+	apply_set_space_symbol(ah, "\001");
+	apply_set_epsilon(ah, "\002");
+	apply_set_separator(ah, "\003");
+        for (;;) {
+	    result = apply_words(ah);
+            if (result == NULL)
+                break;
+	    iface_split_result(result, &upper, &lower);
+	    fprintf(outfile, "%s\t%s\n", upper, lower);
+	    xxfree(upper);
+	    xxfree(lower);
+        }
+	apply_set_space_symbol(ah, " ");
+	apply_set_epsilon(ah, "0");
+	apply_set_separator(ah, ":");
+        apply_reset_enumerator(ah);
+	fclose(outfile);
+    }
+}
+
+int iface_write_att(char *filename) {
+    FILE    *outfile;
+    struct fsm *net;
+    if (!iface_stack_check(1)) {
+	return 1;
+    }
+    net = stack_find_top()->fsm;
+    if (filename == NULL) {
+        outfile = stdout;
+    } else {
+        printf("Writing AT&T file: %s\n",filename);
+        outfile = fopen(filename, "w");
+        if(outfile == NULL) {
+	    fprintf(stderr, "%s: ", filename);
+            perror("File error opening.");
+            return 1;
+        }
+    }
+    net_print_att(net, outfile);
+    if (filename != NULL)
+        fclose(outfile);
+    return 0;
+}
+
+void iface_write_prolog(char *filename) {
+  if (iface_stack_check(1))
+    foma_write_prolog(stack_find_top()->fsm, filename);
+}
+
+void iface_zero_plus() {
+    if (iface_stack_check(1))
+        stack_add(fsm_topsort(fsm_minimize(fsm_kleene_star(stack_pop()))));
+}
+
+static char *sigptr(struct sigma *sigma, int number) {
+    char *mystr;
+    if (number == EPSILON)
+        return "0";
+    if (number == UNKNOWN)
+        return "?";
+    if (number == IDENTITY)
+        return "@";
+
+    for (; sigma != NULL; sigma = sigma->next) {
+        if (sigma->number == number) {
+            if (strcmp(sigma->symbol,"0") == 0)
+                return("\"0\"");
+            if (strcmp(sigma->symbol,"?") == 0)
+                return("\"?\"");
+            if (strcmp(sigma->symbol,"\n") == 0)
+                return("\\n");
+            if (strcmp(sigma->symbol,"\r") == 0)
+                return("\\r");
+            return (sigma->symbol);
+        }
+    }
+    mystr = xxmalloc(sizeof(char)*40);
+    snprintf(mystr, 40, "NONE(%i)",number);
+    return(mystr);
+}
+
+static int print_net(struct fsm *net, char *filename) {
+  struct fsm_state *stateptr;
+  int previous_state = -1, i;
+  int *finals;
+  FILE *out;
+  if (filename == NULL) {
+      out = stdout;
+  } else {
+      if ((out = fopen(filename, "w")) == NULL) {
+          printf("Error writing to file %s. Using stdout.\n", filename);
+          out = stdout;
+      }
+      printf("Writing network to file %s.\n", filename);
+  }
+  fsm_count(net);
+  finals = xxmalloc(sizeof(int)*(net->statecount));
+  stateptr = net->states;
+
+  for (i=0; (stateptr+i)->state_no != -1; i++) {
+    if ((stateptr+i)->final_state == 1) {
+      *(finals+((stateptr+i)->state_no)) = 1;
+    } else {
+      *(finals+((stateptr+i)->state_no)) = 0;
+    }
+    if ((stateptr+i)->in != (stateptr+i)->out) {
+      net->arity = 2;
+    }
+  }
+  print_sigma(net->sigma, out);
+  fprintf(out,"Net: %s\n",net->name);
+  fprintf(out,"Flags: ");
+  if (net->is_deterministic == YES) { fprintf(out,"deterministic ");}
+  if (net->is_pruned == YES) { fprintf(out,"pruned ");}
+  if (net->is_minimized == YES) { fprintf(out,"minimized ");}
+  if (net->is_epsilon_free == YES) { fprintf(out,"epsilon_free ");}
+  if (net->is_loop_free) { fprintf(out,"loop_free "); }
+  if (net->arcs_sorted_in) { fprintf(out,"arcs_sorted_in "); }
+  if (net->arcs_sorted_out) { fprintf(out,"arcs_sorted_out "); }
+  fprintf(out,"\n");
+  fprintf(out,"Arity: %i\n", net->arity);
+  for (; stateptr->state_no != -1; stateptr++) {
+    if (stateptr->state_no != previous_state) {
+      if (stateptr->start_state) {
+          fprintf(out,"S");
+      }
+      if (stateptr->final_state) {
+          fprintf(out,"f");
+      }
+      if (stateptr->in==-1) {
+          fprintf(out,"s%i:\t(no arcs).\n",stateptr->state_no);
+	continue;
+      } else {
+          fprintf(out,"s%i:\t",stateptr->state_no);
+      }
+    }
+    previous_state = stateptr->state_no;
+    if (stateptr->in == stateptr->out) {
+      if (stateptr->in == IDENTITY) {
+          fprintf(out,"@ -> ");
+      } else if (stateptr->in == UNKNOWN) {
+          fprintf(out,"?:? -> ");
+      } else {
+          fprintf(out,"%s -> ",sigptr(net->sigma, stateptr->in));
+      }
+    } else {
+        fprintf(out,"<%s:%s> -> ",sigptr(net->sigma, stateptr->in),sigptr(net->sigma, stateptr->out));
+    }
+    if (*(finals+(stateptr->target)) == 1) {
+        fprintf(out,"f");
+    }
+    fprintf(out,"s%i",stateptr->target);
+    if ((stateptr+1)->state_no == stateptr->state_no) {
+        fprintf(out,", ");
+    } else {
+        fprintf(out,".\n");
+    }
+
+  }
+  if (filename != NULL) {
+      fclose(out);
+  }
+  xxfree(finals);
+  return 0;
+}
+
+void print_mem_size(struct fsm *net) {
+    char size[20];
+    struct sigma *sigma;
+    unsigned int s;
+    float sf;
+    s = 0;
+    for (sigma = net->sigma; sigma != NULL && sigma->number != -1; sigma = sigma->next) {
+        s += strlen(sigma->symbol)+1+sizeof(struct sigma);
+    }
+    s += sizeof(struct fsm);
+    s += sizeof(struct fsm_state) * net->linecount;
+    sf = s;
+    if (s < 1024) {
+        sprintf(size, "%i bytes. ", s);
+    } else if (s >= 1024 && s < 1048576) {
+        sprintf(size, "%.1f kB. ", sf/1024);
+    } else if (s >= 1048576 && s < 1073741824) {
+        sprintf(size, "%.1f MB. ", sf/1048576);
+    } else if (s >= 1073741824) {
+        sprintf(size, "%.1f GB. ", sf/1073741824);
+    }
+    fprintf(stdout, "%s", size);
+    fflush(stdout);
+}
+
+int print_stats(struct fsm *net) {
+    print_mem_size(net);
+    if (net->statecount == 1) { printf("1 state, "); } else { printf("%i states, ",net->statecount); }
+    if (net->arccount == 1)   { printf("1 arc, "); } else { printf("%i arcs, ",net->arccount); }
+    if (net->pathcount == 1)
+        printf("1 path");
+    else if (net->pathcount == -1)
+        printf("Cyclic");
+    else if (net->pathcount == -2)
+        printf("more than %lld paths",LLONG_MAX);
+    else if (net->pathcount == -3)
+        printf("unknown number of paths");
+    else
+        printf("%lld paths",net->pathcount);
+    printf(".\n");
+    return 0;
+}
+
+static int print_sigma(struct sigma *sigma, FILE *out) {
+  int size;
+  fprintf (out,"Sigma:");
+  for (size = 0; sigma != NULL; sigma = sigma->next) {
+      if (sigma->number > 2) {
+          fprintf(out," %s",(sigma->symbol));
+          size++;
+      }
+      if (sigma->number == IDENTITY) {
+          fprintf(out," %s","@");
+      }
+      if (sigma->number == UNKNOWN) {
+          fprintf(out," %s","?");
+      }
+  }
+  fprintf(out,"\n");
+  fprintf(out,"Size: %i.\n",size);
+  return(1);
+}
+
+static int print_dot(struct fsm *net, char *filename) {
+    struct fsm_state *stateptr;
+    FILE *dotfile;
+    int i, j, linelen;
+    short *finals, *printed;
+    
+    fsm_count(net);
+    
+    finals = xxmalloc(sizeof(short)*net->statecount);
+    stateptr = net->states;
+    
+    for (i=0; (stateptr+i)->state_no != -1; i++) {
+        if ((stateptr+i)->final_state == 1) {
+            *(finals+((stateptr+i)->state_no)) = 1;
+        } else {
+            *(finals+((stateptr+i)->state_no)) = 0;
+        }
+    }
+    
+    if (filename != NULL) {
+        dotfile = fopen(filename,"w");
+    } else {
+        dotfile = stdout;
+    }
+
+  fprintf(dotfile,"digraph A {\nrankdir = LR;\n");
+  /* Go through states */
+  for (i=0; i < net->statecount; i++) {
+    if (*(finals+i)) {
+      fprintf(dotfile,"node [shape=doublecircle,style=filled] %i\n",i);
+    } else {
+      fprintf(dotfile,"node [shape=circle,style=filled] %i\n",i);
+    }
+  }
+
+  printed = xxcalloc(net->linecount,sizeof(printed));
+  /* Go through arcs */
+  for (i=0; (stateptr+i)->state_no != -1; i++) {
+      if ((stateptr+i)->target == -1 || printed[i] == 1)
+          continue;
+      fprintf(dotfile,"%i -> %i [label=\"", (stateptr+i)->state_no, (stateptr+i)->target);
+      linelen = 0;
+      for (j=i; (stateptr+j)->state_no == (stateptr+i)->state_no; j++) {
+          if (((stateptr+i)->target == ((stateptr+j)->target)) && printed[j] == 0) {
+              printed[j] = 1;
+
+              if (((stateptr+j)->in == ((stateptr+j)->out)) && (stateptr+j)->out != UNKNOWN ) {
+                  fprintf(dotfile,"%s", escape_string(sigptr(net->sigma, (stateptr+j)->in),'"'));
+                  linelen += strlen((sigptr(net->sigma, (stateptr+j)->in)));
+              } else {
+                  fprintf(dotfile,"<%s:%s>", escape_string(sigptr(net->sigma, (stateptr+j)->in),'"'), escape_string(sigptr(net->sigma, (stateptr+j)->out),'"'));
+                  linelen += strlen((sigptr(net->sigma, (stateptr+j)->in))) + strlen(sigptr(net->sigma, (stateptr+j)->out)) + 3;
+              }
+              if (linelen > 12) {
+                  fprintf(dotfile, "\\n");
+                  linelen = 0;
+              } else {
+                  fprintf(dotfile, " ");
+              }
+          }
+      }
+      fprintf(dotfile,"\"];\n");
+  }
+
+  
+  xxfree(finals);
+  xxfree(printed);
+  fprintf(dotfile, "}\n");
+  if (filename != NULL)
+      fclose(dotfile);
+  return(1);
+}
+
+static int view_net(struct fsm *net) {
+
+  char tmpstr[255];
+  char *dotname;
+#ifndef __APPLE__
+  char *pngname;
+#endif  /* __APPLE__ */
+
+  dotname = strncpy(tmpstr,tempnam(NULL,"foma"), 250);
+  strcat(dotname, ".dot");
+  dotname = xxstrdup(tmpstr);
+  print_dot(net, dotname);
+
+#ifdef __APPLE__
+  sprintf(tmpstr,"/usr/bin/open -a Graphviz %s &",dotname);
+  if (system(tmpstr) == -1)
+      printf("Error opening viewer.\n");
+  
+#endif /* __APPLE__ */
+
+#ifndef __APPLE__
+  pngname = xxstrdup(tempnam(NULL, "foma"));
+  sprintf(tmpstr,"dot -Tpng %s > %s ",dotname,pngname);
+  if (system(tmpstr) == -1)
+      printf("Error writing tempfile.\n");
+  sprintf(tmpstr,"/usr/bin/xdg-open %s 2>/dev/null &",pngname);
+  if (system(tmpstr) == -1)
+      printf("Error opening viewer.\n");
+  xxfree(pngname);
+#endif /* __APPLE__ */
+
+  xxfree(dotname);
+  
+  return(1);
+}
diff --git a/back-ends/foma/cpp-version/int_stack.cc b/back-ends/foma/cpp-version/int_stack.cc
new file mode 100644
index 0000000..1b6bda5
--- /dev/null
+++ b/back-ends/foma/cpp-version/int_stack.cc
@@ -0,0 +1,96 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "foma.h"
+
+#define MAX_STACK 2097152
+#define MAX_PTR_STACK 2097152
+
+static int a[MAX_STACK];
+static int top = -1;
+
+static void *ptr_stack[MAX_PTR_STACK];
+static int ptr_stack_top = -1;
+
+int ptr_stack_isempty() {
+    return ptr_stack_top == -1;
+}
+
+void ptr_stack_clear() {
+    ptr_stack_top = -1;
+}
+
+void *ptr_stack_pop() {
+    return ptr_stack[ptr_stack_top--];
+}
+
+int ptr_stack_isfull() {
+    return (ptr_stack_top == (MAX_PTR_STACK - 1));
+}
+
+void ptr_stack_push(void *ptr) {
+    if (ptr_stack_isfull()) {
+        fprintf(stderr, "Pointer stack full!\n");
+        exit(1);
+    }
+    ptr_stack[++ptr_stack_top] = ptr;
+}
+
+
+int int_stack_isempty() {
+  return top == -1;
+}
+
+void int_stack_clear() {
+  top = -1;
+}
+
+int int_stack_find (int entry) {
+  int i;
+  if (int_stack_isempty()) {
+    return 0;
+  }
+  for(i = 0; i <= top ; i++) {
+    if (entry == a[i]) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+int int_stack_size () {
+  return (top + 1);
+}
+
+void int_stack_push(int c) {
+  if (int_stack_isfull()) {
+    fprintf(stderr, "Stack full!\n");
+    exit(1);
+  }
+  a[++top] = c;
+}
+
+
+int int_stack_pop() {
+  return a[top--];
+}
+
+int int_stack_isfull() {
+  return (top == (MAX_STACK - 1));
+}
diff --git a/back-ends/foma/cpp-version/io.cc b/back-ends/foma/cpp-version/io.cc
new file mode 100644
index 0000000..d17da4e
--- /dev/null
+++ b/back-ends/foma/cpp-version/io.cc
@@ -0,0 +1,1090 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2014 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "foma.h"
+#ifdef ORIGINAL
+#include "zlib.h"
+#else
+  #ifdef ZLIB
+    #include "zlib.h"
+  #endif
+#endif
+
+#define TYPE_TRANSITION 1
+#define TYPE_SYMBOL 2
+#define TYPE_FINAL 3
+#define TYPE_PROPERTY 4
+#define TYPE_END 5
+#define TYPE_ERROR 6
+
+#define READ_BUF_SIZE 4096
+
+struct binaryline {
+    int type;
+    int state;
+    int in;
+    int target;
+    int out;
+    int symbol;
+    char *name;
+    char *value;
+};
+
+extern char *g_att_epsilon;
+
+extern struct defined_networks   *g_defines;
+extern struct defined_functions  *g_defines_f;
+
+struct io_buf_handle {
+    char *io_buf;
+    char *io_buf_ptr;
+};
+
+#ifdef ORIGINAL
+struct io_buf_handle *io_init();
+void io_free(struct io_buf_handle *iobh);
+static int io_gets(struct io_buf_handle *iobh, char *target);
+static size_t io_get_gz_file_size(char *filename);
+static size_t io_get_file_size(char *filename);
+static size_t io_get_regular_file_size(char *filename);
+size_t io_gz_file_to_mem (struct io_buf_handle *iobh, char *filename);
+int foma_net_print(struct fsm *net, gzFile outfile);
+struct fsm *io_net_read(struct io_buf_handle *iobh, char **net_name);
+static INLINE int explode_line (char *buf, int *values);
+#else // #ifdef ORIGINAL
+  struct io_buf_handle *io_init();
+  void io_free(struct io_buf_handle *iobh);
+  #ifdef ZLIB
+    static int io_gets(struct io_buf_handle *iobh, char *target);
+    static size_t io_get_gz_file_size(char *filename);
+    static size_t io_get_file_size(char *filename);
+    static size_t io_get_regular_file_size(char *filename);
+  #endif // ZLIB
+  size_t io_gz_file_to_mem (struct io_buf_handle *iobh, char *filename);
+  #ifdef ZLIB
+    int foma_net_print(struct fsm *net, gzFile outfile);
+  #endif // ZLIB
+  struct fsm *io_net_read(struct io_buf_handle *iobh, char **net_name);
+  #ifdef ZLIB
+    static INLINE int explode_line (char *buf, int *values);
+  #endif
+#endif // #ifdef ORIGINAL
+
+#ifndef ORIGINAL
+  #if defined (_MSC_VER) || (__MINGW32__)
+    #define LONG_LONG_SPECIFIER "%I64d"
+  #else
+    #define LONG_LONG_SPECIFIER "%lld"
+  #endif
+#endif // #ifndef ORIGINAL
+
+#ifndef ORIGINAL
+// HFST addition. Dummy implementations for non static io functions
+// that could be called outside io.c when ZLIB is not defined.
+  #ifndef ZLIB
+    static void io_error() { fprintf(stderr, "IO_C_ERROR\n"); exit(1); }
+    struct io_buf_handle *io_init() {  io_error(); return NULL; }
+    void io_free(struct io_buf_handle *iobh) { io_error(); return; }
+    size_t io_gz_file_to_mem (struct io_buf_handle *iobh, char *filename) {
+      io_error(); return 0; }
+    struct fsm *io_net_read(struct io_buf_handle *iobh, char **net_name) {
+      io_error(); return NULL; }
+    struct fsm *fsm_read_binary_file(char *filename) { io_error(); return NULL; }
+    struct fsm *fsm_read_binary_file_multiple(fsm_read_binary_handle fsrh) {
+      io_error(); return NULL; }
+    fsm_read_binary_handle fsm_read_binary_file_multiple_init(char *filename) {
+      io_error(); return NULL; }
+    struct fsm *read_att(char *filename) { io_error(); return NULL; }
+    struct fsm *fsm_read_prolog(char *filename) { io_error(); return NULL; }
+    int load_defined(struct defined_networks *def, char *filename) { io_error(); return 0; }
+    int save_defined(struct defined_networks *def, char *filename) { io_error(); return 0; }
+    int foma_write_prolog(struct fsm *net, char *filename) { io_error(); return 0; }
+  #endif // #ifndef ZLIB
+#endif // #ifndef ORIGINAL
+
+#if defined(ORIGINAL) || defined(ZLIB)
+void escape_print(FILE *stream, char* string) {
+    int i;
+    if (strchr(string, '"') != NULL) {
+	for (i = 0; *(string+i) != '\0'; i++) {
+	    if (*(string+i) == '"') {
+		fprintf(stream, "\\\"");
+	    } else {
+		fputc(*(string+i), stream);
+	    }
+	}
+    } else {
+	fprintf(stream, "%s", string);
+    }
+}
+
+int foma_write_prolog (struct fsm *net, char *filename) {
+  struct fsm_state *stateptr;
+  int i, *finals, *used_symbols, maxsigma;
+  FILE *out;
+  char *outstring, *instring, identifier[100];
+  
+  if (filename == NULL) {
+    out = stdout;
+  } else {
+    if ((out = fopen(filename, "w")) == NULL) {
+      printf("Error writing to file '%s'. Using stdout.\n", filename);
+      out = stdout;
+    }
+    printf("Writing prolog to file '%s'.\n", filename);
+  }
+  fsm_count(net);
+  maxsigma = sigma_max(net->sigma);
+  used_symbols = xxcalloc(maxsigma+1,sizeof(int));
+  finals = xxmalloc(sizeof(int)*(net->statecount));
+  stateptr = net->states;
+  identifier[0] = '\0';
+
+  strcpy(identifier, net->name);
+
+  /* Print identifier */
+  fprintf(out, "%s%s%s", "network(",identifier,").\n");
+
+  for (i=0; (stateptr+i)->state_no != -1; i++) {
+    if ((stateptr+i)->final_state == 1) {
+      *(finals+((stateptr+i)->state_no)) = 1;
+    } else {
+      *(finals+((stateptr+i)->state_no)) = 0;
+    }
+    if ((stateptr+i)->in != -1) {
+      *(used_symbols+((stateptr+i)->in)) = 1;
+    }
+    if ((stateptr+i)->out != -1) {
+      *(used_symbols+((stateptr+i)->out)) = 1;
+    }
+
+  }
+
+  for (i = 3; i <= maxsigma; i++) {
+    if (*(used_symbols+i) == 0) {
+      instring = sigma_string(i, net->sigma);
+      if (strcmp(instring,"0") == 0) {
+	  instring = "%0";
+      }
+      fprintf(out, "symbol(%s, \"", identifier);
+      escape_print(out, instring);
+      fprintf(out, "\").\n");
+
+    }
+  }
+  
+  for (; stateptr->state_no != -1; stateptr++) {
+    if (stateptr->target == -1)
+      continue;
+    fprintf(out, "arc(%s, %i, %i, ", identifier, stateptr->state_no, stateptr->target);
+    if      (stateptr->in == 0) instring = "0";
+    else if (stateptr->in == 1) instring = "?";
+    else if (stateptr->in == 2) instring = "?";
+    else instring = sigma_string(stateptr->in, net->sigma);
+    if      (stateptr->out == 0) outstring = "0";
+    else if (stateptr->out == 1) outstring = "?";
+    else if (stateptr->out == 2) outstring = "?";
+    else outstring = sigma_string(stateptr->out, net->sigma);
+
+    if (strcmp(instring,"0") == 0 && stateptr->in != 0) instring = "%0";
+    if (strcmp(outstring,"0") == 0 && stateptr->out != 0) outstring = "%0";
+    if (strcmp(instring,"?") == 0 && stateptr->in > 2) instring = "%?";
+    if (strcmp(outstring,"?") == 0 && stateptr->in > 2) outstring = "%?";
+    /* Escape quotes */
+    
+    if (net->arity == 2 && stateptr->in == IDENTITY && stateptr->out == IDENTITY) {
+      fprintf(out, "\"?\").\n");
+    }
+    else if (net->arity == 2 && stateptr->in == stateptr->out && stateptr->in != UNKNOWN) {
+	fprintf(out, "\"");
+	escape_print(out, instring);
+	fprintf(out, "\").\n");
+    }
+    else if (net->arity == 2) {
+      fprintf(out, "\"");
+      escape_print(out, instring);
+      fprintf(out, "\":\"");
+      escape_print(out, outstring);
+      fprintf(out, "\").\n");
+    }
+    else if (net->arity == 1) {
+	fprintf(out, "\"");
+	escape_print(out, instring);
+	fprintf(out, "\").\n");
+    }
+  }
+
+  for (i = 0; i < net->statecount; i++) {
+    if (*(finals+i)) {
+      fprintf(out, "final(%s, %i).\n", identifier, i);
+    }
+  }
+  if (filename != NULL) {
+      fclose(out);
+  }
+  xxfree(finals);
+  xxfree(used_symbols);
+  return 1;
+}
+
+struct fsm *read_att(char *filename) {
+
+    struct fsm_construct_handle *h;
+    struct fsm *net;
+    int i;
+    char inword[1024], delimiters[] = "\t", *tokens[6];
+    FILE *INFILE;
+
+    INFILE = fopen(filename, "r");
+    if (INFILE == NULL) {
+        return(NULL);
+    }
+
+    h = fsm_construct_init(filename);
+    while (fgets(inword, 1024, INFILE) != NULL) {
+        if (inword[strlen(inword)-1] == '\n') {
+            inword[strlen(inword)-1] = '\0';
+        }
+        tokens[0] = strtok(inword, delimiters);
+        i = 0;
+        if (tokens[0] != NULL) {
+            i = 1;
+            for ( ; ; ) {
+                tokens[i] = strtok(NULL, delimiters);
+                if (tokens[i] == NULL) {
+                    break;
+                }
+                i++;
+                if (i == 6)
+                    break;
+            }
+        }
+        if (i == 0) { continue; }
+        if (i >= 4) {
+            if (strcmp(tokens[2],g_att_epsilon) == 0)
+                tokens[2] = "@_EPSILON_SYMBOL_@";
+            if (strcmp(tokens[3],g_att_epsilon) == 0)
+                tokens[3] = "@_EPSILON_SYMBOL_@";
+
+            fsm_construct_add_arc(h, atoi(tokens[0]), atoi(tokens[1]), tokens[2], tokens[3]);
+        }
+        else if (i <= 3 && i > 0) {
+            fsm_construct_set_final(h,atoi(tokens[0]));
+        }
+    }
+    fsm_construct_set_initial(h,0);
+    fclose(INFILE);
+    net = fsm_construct_done(h);
+    fsm_count(net);
+    net = fsm_topsort(net);
+    return(net);
+}
+
+struct fsm *fsm_read_prolog (char *filename) {
+    char buf [1024], temp [1024], in [128], out[128], *temp_ptr, *temp_ptr2;
+    int arity, source, target, has_net;
+    struct fsm *outnet;
+    struct fsm_construct_handle *outh = NULL;
+    FILE *prolog_file;
+    
+    has_net = 0;
+    prolog_file = fopen(filename, "r");
+    if (prolog_file == NULL) {
+	return NULL;
+    }
+
+    while (fgets(buf, 1023, prolog_file) != NULL) {
+	if (strstr(buf, "network(") == buf) {
+	    /* Extract network name */
+	    if (has_net == 1) {
+		perror("WARNING: prolog file contains multiple nets. Only returning the first one.\n");
+		break;
+	    } else {
+		has_net = 1;
+	    }
+	    temp_ptr = strstr(buf, "network(")+8;
+	    temp_ptr2 = strstr(buf, ").");
+	    strncpy(temp, temp_ptr, (temp_ptr2 - temp_ptr));
+	    temp[(temp_ptr2-temp_ptr)] = '\0';
+	    
+	    /* Start network */
+	    outh = fsm_construct_init(temp);
+	}
+	if (strstr(buf, "final(") == buf) {
+	    temp_ptr = strstr(buf, " ");
+	    temp_ptr++;
+	    temp_ptr2 = strstr(temp_ptr, ").");
+	    strncpy(temp, temp_ptr, (temp_ptr2 - temp_ptr));
+	    temp[(temp_ptr2-temp_ptr)] = '\0';
+	    
+	    fsm_construct_set_final(outh, atoi(temp));
+	}
+	if (strstr(buf, "symbol(") == buf) {
+	    temp_ptr = strstr(buf, ", \"")+3;
+	    temp_ptr2 = strstr(temp_ptr, "\").");
+	    strncpy(temp, temp_ptr, (temp_ptr2 - temp_ptr));
+	    temp[(temp_ptr2-temp_ptr)] = '\0';
+	    if (strcmp(temp, "%0") == 0)
+		strcpy(temp, "0");
+	    //printf("special: %s\n",temp);
+	    
+	    if (fsm_construct_check_symbol(outh, temp) == -1) {
+		fsm_construct_add_symbol(outh, temp);
+	    }
+	    continue;
+	}
+	if (strstr(buf, "arc(") == buf) {
+	    in[0] = '\0';
+	    out[0] = '\0';
+	    
+	    if (strstr(buf, "\":\"") == NULL || strstr(buf, ", \":\").") != NULL) {
+		arity = 1;
+	    } else {
+		arity = 2;
+	    }
+	    
+	    /* Get source */
+	    temp_ptr = strstr(buf, " ");
+	    temp_ptr++;
+	    temp_ptr2 = strstr(temp_ptr, ",");
+	    strncpy(temp, temp_ptr, (temp_ptr2 - temp_ptr));
+	    temp[(temp_ptr2-temp_ptr)] = '\0';
+	    source = atoi(temp);
+	    
+	    /* Get target */
+	    temp_ptr = strstr(temp_ptr2, " ");
+	    temp_ptr++;
+	    temp_ptr2 = strstr(temp_ptr, ",");
+	    strncpy(temp, temp_ptr, (temp_ptr2 - temp_ptr));
+	    temp[(temp_ptr2-temp_ptr)] = '\0';
+	    target = atoi(temp);
+	    
+	    temp_ptr = strstr(temp_ptr2, "\"");
+	    temp_ptr++;
+	    if (arity == 2)  {
+		temp_ptr2 = strstr(temp_ptr, "\":");
+	    } else {
+		temp_ptr2 = strstr(temp_ptr, "\").");
+	    }
+	    strncpy(in, temp_ptr, (temp_ptr2 - temp_ptr));
+	    in[(temp_ptr2 - temp_ptr)] = '\0';
+	    
+	    if (arity == 2) {
+		temp_ptr = strstr(temp_ptr2, ":\"");
+		temp_ptr += 2;
+		temp_ptr2 = strstr(temp_ptr, "\").");
+		strncpy(out, temp_ptr, (temp_ptr2 - temp_ptr));
+		out[(temp_ptr2 - temp_ptr)] = '\0';
+	    }
+	    if (arity == 1 && (strcmp(in, "?") == 0)) {
+		strcpy(in,"@_IDENTITY_SYMBOL_@");
+	    }
+	    if (arity == 2 && (strcmp(in, "?") == 0)) {
+		strcpy(in,"@_UNKNOWN_SYMBOL_@");
+	    }
+	    if (arity == 2 && (strcmp(out, "?") == 0)) {
+		strcpy(out,"@_UNKNOWN_SYMBOL_@");
+	    }
+	    if (strcmp(in, "0") == 0) {
+		strcpy(in,"@_EPSILON_SYMBOL_@");
+	    }
+	    if (strcmp(out, "0") == 0) {
+		strcpy(out,"@_EPSILON_SYMBOL_@");
+	    }
+	    if (strcmp(in, "%0") == 0) {
+		strcpy(in,"0");
+	    }
+	    if (strcmp(out, "%0") == 0) {
+		strcpy(out,"0");
+	    }
+	    if (strcmp(in, "%?") == 0) {
+		strcpy(in,"?");
+	    }
+	    if (strcmp(out, "%?") == 0) {
+		strcpy(out,"?");
+	    }
+	    
+	    if (arity == 1) {
+		fsm_construct_add_arc(outh, source, target, in, in);
+	    } else {
+		fsm_construct_add_arc(outh, source, target, in, out);
+	    }
+	}
+    }
+    fclose(prolog_file);
+    if (has_net == 1) {
+	fsm_construct_set_initial(outh, 0);
+	outnet = fsm_construct_done(outh);
+	fsm_topsort(outnet);
+	return(outnet);
+    } else {
+	return(NULL);
+    }
+}
+
+struct io_buf_handle *io_init() {
+    struct io_buf_handle *iobh;
+    iobh = xxmalloc(sizeof(struct io_buf_handle));
+    (iobh->io_buf) = NULL;
+    (iobh->io_buf_ptr) = NULL;
+    return(iobh);
+}
+
+void io_free(struct io_buf_handle *iobh) {
+    if (iobh->io_buf != NULL) {
+        xxfree(iobh->io_buf);
+        (iobh->io_buf) = NULL;
+    }
+    xxfree(iobh);
+}
+
+#endif // #if defined(ORIGINAL) || defined(ZLIB)
+
+char *spacedtext_get_next_line(char **text) {
+    char *t, *ret;
+    ret = *text;
+    if (**text == '\0')
+	return NULL;
+    for (t = *text; *t != '\0' && *t != '\n'; t++) {
+    }
+    if (*t == '\0')
+	*text = t;
+    else
+	*text = t+1;
+    *t = '\0';
+    return(ret);
+}
+
+char *spacedtext_get_next_token(char **text) {
+    char *t, *ret;
+    if (**text == '\0' || **text == '\n')
+	return NULL;
+    for ( ; **text == ' ' ; (*text)++) {
+    }
+    ret = *text;
+    for (t = *text; *t != '\0' && *t != '\n' && *t != ' '; t++) {
+    }
+    if (*t == '\0' || *t == '\n')
+	*text = t;
+    else
+	*text = t+1;
+    *t = '\0';
+    return(ret);
+}
+
+struct fsm *fsm_read_spaced_text_file(char *filename) {
+    struct fsm_trie_handle *th;
+    char *text, *textorig, *insym, *outsym, *t1, *t2, *l1, *l2;
+
+    text = textorig = file_to_mem(filename);
+    
+    if (text == NULL)
+	return NULL;
+    th = fsm_trie_init();
+    for (;;) {
+	for ( ; *text != '\0' && *text == '\n'; text++) { }
+	t1 = spacedtext_get_next_line(&text);
+	if (t1 == NULL)
+	    break;
+	if (strlen(t1) == 0)
+	    continue;
+	t2 = spacedtext_get_next_line(&text);
+	if (t2 == NULL || strlen(t2) == 0) {
+	    for (l1 = t1; (insym = spacedtext_get_next_token(&l1)) != NULL; ) {
+		if (strcmp(insym, "0") == 0)
+		    fsm_trie_symbol(th,  "@_EPSILON_SYMBOL_@", "@_EPSILON_SYMBOL_@");
+		else if (strcmp(insym, "%0") == 0)
+		    fsm_trie_symbol(th,  "0", "0");
+		else
+		    fsm_trie_symbol(th,  insym, insym);
+	    }
+	    fsm_trie_end_word(th);
+	} else {
+	    for (l1 = t1, l2 = t2; ; ) {
+		insym = spacedtext_get_next_token(&l1);
+		outsym = spacedtext_get_next_token(&l2);
+		if (insym == NULL && outsym == NULL)
+		    break;
+		if (insym == NULL || strcmp(insym, "0") == 0)
+		    insym = "@_EPSILON_SYMBOL_@";
+		if (strcmp(insym, "%0") == 0)
+		    insym = "0";
+		if (outsym == NULL || strcmp(outsym, "0") == 0)
+		    outsym = "@_EPSILON_SYMBOL_@";
+		if (strcmp(outsym, "%0") == 0)
+		    outsym = "0";
+		fsm_trie_symbol(th, insym, outsym);
+	    }
+	    fsm_trie_end_word(th);
+	}
+    }
+    xxfree(textorig);
+    return(fsm_trie_done(th));
+}
+
+struct fsm *fsm_read_text_file(char *filename) {
+    struct fsm_trie_handle *th;
+    char *text, *textp1, *textp2;
+    int lastword;
+
+    text = file_to_mem(filename);
+    if (text == NULL) {
+	return NULL;
+    }
+    textp1 = text;
+    th = fsm_trie_init();
+
+    for (lastword = 0 ; lastword == 0 ; textp1 = textp2+1) {
+	for (textp2 = textp1 ; *textp2 != '\n' && *textp2 != '\0'; textp2++) {
+	}
+	if (*textp2 == '\0') {
+	    lastword = 1;
+	    if (textp2 == textp1)
+		break;
+	}
+	*textp2 = '\0';
+	if (strlen(textp1) > 0)
+	    fsm_trie_add_word(th, textp1);
+    }
+    xxfree(text);
+    return(fsm_trie_done(th));
+}
+
+#if defined(ORIGINAL) || defined(ZLIB)
+
+int fsm_write_binary_file(struct fsm *net, char *filename) {
+    gzFile outfile;
+    if ((outfile = gzopen(filename,"wb")) == NULL) {
+	return(1);
+    }
+    foma_net_print(net, outfile);
+    gzclose(outfile);
+    return(0);
+}
+
+struct fsm *fsm_read_binary_file_multiple(fsm_read_binary_handle fsrh) {
+    char *net_name;
+    struct fsm *net;
+    struct io_buf_handle *iobh;
+    iobh = (struct io_buf_handle *) fsrh;
+    net = io_net_read(iobh, &net_name);
+    if (net == NULL) {
+	io_free(iobh);
+	return(NULL);
+    } else {
+	xxfree(net_name);
+	return(net);
+    }
+}
+
+fsm_read_binary_handle fsm_read_binary_file_multiple_init(char *filename) {
+
+    struct io_buf_handle *iobh;
+    fsm_read_binary_handle fsm_read_handle;
+
+    iobh = io_init();
+    if (io_gz_file_to_mem(iobh, filename) == 0) {
+	io_free(iobh);
+	return NULL;
+    }
+    fsm_read_handle = (void *) iobh;
+    return(fsm_read_handle);
+}
+
+struct fsm *fsm_read_binary_file(char *filename) {
+    char *net_name;
+    struct fsm *net;
+    struct io_buf_handle *iobh;
+    iobh = io_init();
+    if (io_gz_file_to_mem(iobh, filename) == 0) {
+	io_free(iobh);
+        return NULL;
+    }
+    net = io_net_read(iobh, &net_name);
+    io_free(iobh);
+    return(net);
+}
+
+int save_defined(struct defined_networks *def, char *filename) {
+    struct defined_networks *d;
+    gzFile outfile;
+    if (def == NULL) {
+        fprintf(stderr, "No defined networks.\n");
+        return(0);
+    }
+    if ((outfile = gzopen(filename, "wb")) == NULL) {
+        printf("Error opening file %s for writing.\n", filename);
+        return(-1);
+    }
+    printf("Writing definitions to file %s.\n", filename);
+    for (d = def; d != NULL; d = d->next) {
+        strcpy(d->net->name, d->name);
+        foma_net_print(d->net, outfile);
+    }
+    gzclose(outfile);
+    return(1);
+}
+
+int load_defined(struct defined_networks *def, char *filename) {
+    struct fsm *net;
+    char *net_name;
+    struct io_buf_handle *iobh;
+
+    iobh = io_init();
+    printf("Loading definitions from %s.\n",filename);
+    if (io_gz_file_to_mem(iobh, filename) == 0) {
+        fprintf(stderr, "File error.\n");
+	io_free(iobh);
+        return 0;
+    }
+    while ((net = io_net_read(iobh, &net_name)) != NULL) {
+        add_defined(def, net, net_name);
+    }
+    io_free(iobh);
+    return(1);
+}
+
+static INLINE int explode_line(char *buf, int *values) {
+    int i, j, items;
+    j = i = items = 0;
+    for (;;) {
+        for (i = j; *(buf+j) != ' ' && *(buf+j) != '\0'; j++) { }
+        if (*(buf+j) == '\0') {
+            *(values+items) = atoi(buf+i);
+            items++;
+            break;
+        } else{
+            *(buf+j) = '\0';
+            *(values+items) = atoi(buf+i);
+            items++;
+            j++;
+        }
+    }
+    return(items);
+}
+
+/* The file format we use is an extremely simple text format */
+/* which is gzip compressed through libz and consists of the following sections: */
+
+/* ##foma-net VERSION##*/
+/* ##props## */
+/* PROPERTIES LINE */
+/* ##sigma## */
+/* ...SIGMA LINES... */
+/* ##states## */
+/* ...TRANSITION LINES... */
+/* ##end## */
+
+/* Several networks may be concatenated in one file */
+
+/* The initial identifier is "##foma-net 1.0##" */
+/* where 1.0 is the version number for the file format */
+/* followed by the line "##props##" */
+/* which is followed by a line of space separated integers */
+/* which correpond to: */
+
+/* arity arccount statecount linecount finalcount pathcount is_deterministic */
+/* is_pruned is_minimized is_epsilon_free is_loop_free is_completed name  */
+
+/* where name is used if defined networks are saved/loaded */
+
+/* Following the props line, we accept anything (for future expansion) */
+/* until we find ##sigma## */
+
+/* the section beginning with "##sigma##" consists of lines with two fields: */
+/* number string */
+/* correponding to the symbol number and the symbol string */
+
+/* the section beginning with "##states##" consists of lines of ASCII integers */
+/* with 2-5 fields to avoid some redundancy in every line corresponding to a */
+/* transition where otherwise state numbers would be unnecessarily repeated and */
+/* out symbols also (if in = out as is the case for recognizers/simple automata) */
+
+/* The information depending on the number of fields in the lines is as follows: */
+
+/* 2: in target (here state_no is the same as the last mentioned one and out = in) */
+/* 3: in out target (again, state_no is the same as the last mentioned one) */
+/* 4: state_no in target final_state (where out = in) */
+/* 5: state_no in out target final_state */
+
+/* There is no harm in always using 5 fields; however this will take up more space */
+
+/* As in struct fsm_state, states without transitions are represented as a 4-field: */
+/* state_no -1 -1 final_state (since in=out for 4-field lines, out = -1 as well) */
+
+/* AS gzopen will read uncompressed files as well, one can gunzip a file */
+/* that contains a network and still read it */
+
+struct fsm *io_net_read(struct io_buf_handle *iobh, char **net_name) {
+
+    char buf[READ_BUF_SIZE];
+    struct fsm *net;
+    struct fsm_state *fsm;
+    
+    char *new_symbol;
+    int i, items, new_symbol_number, laststate, lineint[5], *cm;
+    int extras;
+    char last_final = '1';
+
+    if (io_gets(iobh, buf) == 0) {
+        return NULL;
+    }
+    
+    net = fsm_create("");
+
+    if (strcmp(buf, "##foma-net 1.0##") != 0) {
+	fsm_destroy(net);
+        perror("File format error foma!\n");
+        return NULL;
+    }
+    io_gets(iobh, buf);
+    if (strcmp(buf, "##props##") != 0) {
+        perror("File format error props!\n");
+	fsm_destroy(net);
+        return NULL;
+    }
+    /* Properties */
+    io_gets(iobh, buf);
+    extras = 0;
+#ifdef ORIGINAL
+    sscanf(buf, "%i %i %i %i %i %lld %i %i %i %i %i %i %s", &net->arity, &net->arccount, &net->statecount, &net->linecount, &net->finalcount, &net->pathcount, &net->is_deterministic, &net->is_pruned, &net->is_minimized, &net->is_epsilon_free, &net->is_loop_free, &extras, buf);
+#else
+    sscanf(buf, "%i %i %i %i %i "LONG_LONG_SPECIFIER" %i %i %i %i %i %i %s", &net->arity, &net->arccount, &net->statecount, &net->linecount, &net->finalcount, &net->pathcount, &net->is_deterministic, &net->is_pruned, &net->is_minimized, &net->is_epsilon_free, &net->is_loop_free, &extras, buf);
+#endif
+    strcpy(net->name, buf);
+    *net_name = xxstrdup(buf);
+    io_gets(iobh, buf);
+
+    net->is_completed = (extras & 3);
+    net->arcs_sorted_in = (extras & 12) >> 2;
+    net->arcs_sorted_out = (extras & 48) >> 4;
+
+    /* Sigma */
+    while (strcmp(buf, "##sigma##") != 0) { /* Loop until we encounter ##sigma## */
+        if (buf[0] == '\0') {
+	  printf("File format error at sigma definition!\n");
+	  fsm_destroy(net);
+	  return NULL;
+        }
+        io_gets(iobh, buf);
+    }
+
+    for (;;) {
+        io_gets(iobh, buf);
+        if (buf[0] == '#') break;
+        if (buf[0] == '\0') continue;
+        new_symbol = strstr(buf, " ");
+	new_symbol[0] = '\0';
+	new_symbol++;
+	if (new_symbol[0] == '\0') {
+	    sscanf(buf,"%i", &new_symbol_number);
+	    sigma_add_number(net->sigma, "\n", new_symbol_number);
+	} else {
+	    sscanf(buf,"%i", &new_symbol_number);
+	    sigma_add_number(net->sigma, new_symbol, new_symbol_number);
+	}
+    }
+
+    /* States */
+    if (strcmp(buf, "##states##") != 0) {
+        printf("File format error!\n");
+        return NULL;
+    }
+    net->states = xxmalloc(net->linecount*sizeof(struct fsm_state));
+    fsm = net->states;
+    laststate = -1;
+    for (i=0; ;i++) {
+        io_gets(iobh, buf);
+        if (buf[0] == '#') break;
+
+        /* scanf is just too slow here */
+
+        //items = sscanf(buf, "%i %i %i %i %i",&lineint[0], &lineint[1], &lineint[2], &lineint[3], &lineint[4]);
+
+        items = explode_line(buf, &lineint[0]);
+
+        switch (items) {
+        case 2:
+            (fsm+i)->state_no = laststate;
+            (fsm+i)->in = lineint[0];
+            (fsm+i)->out = lineint[0];
+            (fsm+i)->target = lineint[1];
+            (fsm+i)->final_state = last_final;
+            break;
+        case 3:
+            (fsm+i)->state_no = laststate;
+            (fsm+i)->in = lineint[0];
+            (fsm+i)->out = lineint[1];
+            (fsm+i)->target = lineint[2];
+            (fsm+i)->final_state = last_final;
+            break;
+        case 4:
+            (fsm+i)->state_no = lineint[0];
+            (fsm+i)->in = lineint[1];
+            (fsm+i)->out = lineint[1];
+            (fsm+i)->target = lineint[2];
+            (fsm+i)->final_state = lineint[3];
+            laststate = lineint[0];
+            last_final = lineint[3];
+            break;
+        case 5:
+            (fsm+i)->state_no = lineint[0];
+            (fsm+i)->in = lineint[1];
+            (fsm+i)->out = lineint[2];
+            (fsm+i)->target = lineint[3];
+            (fsm+i)->final_state = lineint[4];
+            laststate = lineint[0];
+            last_final = lineint[4];
+            break;
+        default:
+            printf("File format error\n");
+            return NULL;
+        }
+        if (laststate > 0) {
+            (fsm+i)->start_state = 0;
+        } else if (laststate == -1) {
+            (fsm+i)->start_state = -1;
+        } else {
+            (fsm+i)->start_state = 1;
+        }
+
+    }
+    if (strcmp(buf, "##cmatrix##") == 0) {
+        cmatrix_init(net);
+        cm = net->medlookup->confusion_matrix;
+        for (;;) {
+            io_gets(iobh, buf);
+            if (buf[0] == '#') break;
+            sscanf(buf,"%i", &i);
+            *cm = i;
+            cm++;
+        }
+    }
+    if (strcmp(buf, "##end##") != 0) {
+        printf("File format error!\n");
+        return NULL;
+    }
+    return(net);
+}
+
+static int io_gets(struct io_buf_handle *iobh, char *target) {
+    int i;
+    for (i = 0; *((iobh->io_buf_ptr)+i) != '\n' && *((iobh->io_buf_ptr)+i) != '\0'; i++) {
+        *(target+i) = *((iobh->io_buf_ptr)+i);
+    }
+    *(target+i) = '\0';
+    if (*((iobh->io_buf_ptr)+i) == '\0')
+    (iobh->io_buf_ptr) = (iobh->io_buf_ptr) + i;
+    else
+        (iobh->io_buf_ptr) = (iobh->io_buf_ptr) + i + 1;
+
+    return(i);
+}
+
+int foma_net_print(struct fsm *net, gzFile outfile) {
+    struct sigma *sigma;
+    struct fsm_state *fsm;
+    int i, maxsigma, laststate, *cm, extras;
+
+    /* Header */
+    gzprintf(outfile, "%s","##foma-net 1.0##\n");
+
+    /* Properties */
+    gzprintf(outfile, "%s","##props##\n");
+
+    extras = (net->is_completed) | (net->arcs_sorted_in << 2) | (net->arcs_sorted_out << 4);
+ 
+#ifdef ORIGINAL
+    gzprintf(outfile,
+	     "%i %i %i %i %i %lld %i %i %i %i %i %i %s\n", net->arity, net->arccount, net->statecount, net->linecount, net->finalcount, net->pathcount, net->is_deterministic, net->is_pruned, net->is_minimized, net->is_epsilon_free, net->is_loop_free, extras, net->name);
+#else
+    gzprintf(outfile,
+	     "%i %i %i %i %i "LONG_LONG_SPECIFIER" %i %i %i %i %i %i %s\n", net->arity, net->arccount, net->statecount, net->linecount, net->finalcount, net->pathcount, net->is_deterministic, net->is_pruned, net->is_minimized, net->is_epsilon_free, net->is_loop_free, extras, net->name);
+#endif
+    
+    /* Sigma */
+    gzprintf(outfile, "%s","##sigma##\n");
+    for (sigma = net->sigma; sigma != NULL && sigma->number != -1; sigma = sigma->next) {
+        gzprintf(outfile, "%i %s\n",sigma->number, sigma->symbol);
+    }
+
+    /* State array */
+    laststate = -1;
+    gzprintf(outfile, "%s","##states##\n");
+    for (fsm = net->states; fsm->state_no !=-1; fsm++) {
+        if (fsm->state_no != laststate) {
+            if (fsm->in != fsm->out) {
+                gzprintf(outfile, "%i %i %i %i %i\n",fsm->state_no, fsm->in, fsm->out, fsm->target, fsm->final_state);
+            } else {
+                gzprintf(outfile, "%i %i %i %i\n",fsm->state_no, fsm->in, fsm->target, fsm->final_state);
+            }
+        } else {
+            if (fsm->in != fsm->out) {
+                gzprintf(outfile, "%i %i %i\n", fsm->in, fsm->out, fsm->target);
+            } else {
+                gzprintf(outfile, "%i %i\n", fsm->in, fsm->target);
+            }
+        }
+        laststate = fsm->state_no;
+    }
+    /* Sentinel for states */
+    gzprintf(outfile, "-1 -1 -1 -1 -1\n");
+
+    /* Store confusion matrix */
+    if (net->medlookup != NULL && net->medlookup->confusion_matrix != NULL) {
+
+        gzprintf(outfile, "%s","##cmatrix##\n");
+        cm = net->medlookup->confusion_matrix;
+        maxsigma = sigma_max(net->sigma)+1;
+        for (i=0; i < maxsigma*maxsigma; i++) {
+            gzprintf(outfile, "%i\n", *(cm+i));
+        }
+    }
+
+    /* End */
+    gzprintf(outfile, "%s","##end##\n");
+    return(1);
+}
+
+#endif // #if defined(ORIGINAL) || defined(ZLIB)
+
+int net_print_att(struct fsm *net, FILE *outfile) {
+    struct fsm_state *fsm;
+    struct fsm_sigma_list *sl;
+    int i, prev;
+
+    fsm = net->states;
+    sl = sigma_to_list(net->sigma);
+    if (sigma_max(net->sigma) >= 0) {
+        (sl+0)->symbol = g_att_epsilon;
+    }
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1) {
+            fprintf(outfile, "%i\t%i\t%s\t%s\n",(fsm+i)->state_no,(fsm+i)->target, (sl+(fsm+i)->in)->symbol, (sl+(fsm+i)->out)->symbol);
+        }
+    }
+    prev = -1;
+    for (i=0; (fsm+i)->state_no != -1; prev = (fsm+i)->state_no, i++) {
+        if ((fsm+i)->state_no != prev && (fsm+i)->final_state == 1) {
+            fprintf(outfile, "%i\n",(fsm+i)->state_no);
+        }
+    }
+    xxfree(sl);
+    return(1);
+}
+
+#if defined(ORIGINAL) || defined(ZLIB)
+
+static size_t io_get_gz_file_size(char *filename) {
+
+    FILE    *infile;
+    size_t    numbytes;
+    unsigned char bytes[4];
+    unsigned int ints[4], i;
+
+    /* The last four bytes in a .gz file shows the size of the uncompressed data */
+    infile = fopen(filename, "r");
+    fseek(infile, -4, SEEK_END);
+    if (fread(&bytes, 1, 4, infile) != 4) // value of fread was not checked in foma, this is an HFST addition
+      return -1;
+    fclose(infile);
+    for (i = 0 ; i < 4 ; i++) {
+        ints[i] = bytes[i];
+    }
+    numbytes = ints[0] | (ints[1] << 8) | (ints[2] << 16 ) | (ints[3] << 24);
+    return(numbytes);
+}
+
+static size_t io_get_regular_file_size(char *filename) {
+
+    FILE    *infile;
+    size_t    numbytes;
+
+    infile = fopen(filename, "r");
+    fseek(infile, 0L, SEEK_END);
+    numbytes = ftell(infile);
+    fclose(infile);
+    return(numbytes);
+}
+
+
+static size_t io_get_file_size(char *filename) {
+    gzFile FILE;
+    size_t size;
+    FILE = gzopen(filename, "r");
+    if (FILE == NULL) {
+        return(0);
+    }
+    if (gzdirect(FILE) == 1) {
+        gzclose(FILE);
+        size = io_get_regular_file_size(filename);
+    } else {
+        gzclose(FILE);
+        size = io_get_gz_file_size(filename);
+    }
+    return(size);
+}
+
+size_t io_gz_file_to_mem(struct io_buf_handle *iobh, char *filename) {
+
+    size_t size;
+    gzFile FILE;
+
+    size = io_get_file_size(filename);
+    if (size == 0) {
+        return 0;
+    }
+    (iobh->io_buf) = xxmalloc((size+1)*sizeof(char));
+    FILE = gzopen(filename, "rb");
+    gzread(FILE, iobh->io_buf, size);
+    gzclose(FILE);
+    *((iobh->io_buf)+size) = '\0';
+    iobh->io_buf_ptr = iobh->io_buf;
+    return(size);
+}
+
+#endif // #if defined(ORIGINAL) || defined(ZLIB)
+
+char *file_to_mem(char *name) {
+    FILE    *infile;
+    size_t    numbytes;
+    char *buffer;
+    infile = fopen(name, "r");
+    if(infile == NULL) {
+        printf("Error opening file '%s'\n",name);
+        return NULL;
+    }
+    fseek(infile, 0L, SEEK_END);
+    numbytes = ftell(infile);
+    fseek(infile, 0L, SEEK_SET);
+    buffer = (char*)xxmalloc((numbytes+1) * sizeof(char));
+    if(buffer == NULL) {
+        printf("Error reading file '%s'\n",name);
+        return NULL;
+    }
+    if (fread(buffer, sizeof(char), numbytes, infile) != numbytes) {
+        printf("Error reading file '%s'\n",name);
+        return NULL;
+    }
+    fclose(infile);
+    *(buffer+numbytes)='\0';
+    return(buffer);
+}
diff --git a/back-ends/foma/cpp-version/lex.cmatrix.cc b/back-ends/foma/cpp-version/lex.cmatrix.cc
new file mode 100644
index 0000000..2e254a0
--- /dev/null
+++ b/back-ends/foma/cpp-version/lex.cmatrix.cc
@@ -0,0 +1,2092 @@
+
+#line 3 "lex.cmatrix.c"
+
+#define  YY_INT_ALIGNED short
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer cmatrix_create_buffer
+#define yy_delete_buffer cmatrix_delete_buffer
+#define yy_flex_debug cmatrix_flex_debug
+#define yy_init_buffer cmatrix_init_buffer
+#define yy_flush_buffer cmatrix_flush_buffer
+#define yy_load_buffer_state cmatrix_load_buffer_state
+#define yy_switch_to_buffer cmatrix_switch_to_buffer
+#define yyin cmatrixin
+#define yyleng cmatrixleng
+#define yylex cmatrixlex
+#define yylineno cmatrixlineno
+#define yyout cmatrixout
+#define yyrestart cmatrixrestart
+#define yytext cmatrixtext
+#define yywrap cmatrixwrap
+#define yyalloc cmatrixalloc
+#define yyrealloc cmatrixrealloc
+#define yyfree cmatrixfree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cmatrixrestart(cmatrixin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int cmatrixleng;
+
+extern FILE *cmatrixin, *cmatrixout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up cmatrixtext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up cmatrixtext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via cmatrixrestart()), so that the user can continue scanning by
+	 * just pointing cmatrixin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when cmatrixtext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int cmatrixleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow cmatrixwrap()'s to do buffer switches
+ * instead of setting up a fresh cmatrixin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void cmatrixrestart (FILE *input_file  );
+void cmatrix_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE cmatrix_create_buffer (FILE *file,int size  );
+void cmatrix_delete_buffer (YY_BUFFER_STATE b  );
+void cmatrix_flush_buffer (YY_BUFFER_STATE b  );
+void cmatrixpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void cmatrixpop_buffer_state (void );
+
+static void cmatrixensure_buffer_stack (void );
+static void cmatrix_load_buffer_state (void );
+static void cmatrix_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER cmatrix_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE cmatrix_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE cmatrix_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE cmatrix_scan_bytes (yyconst char *bytes,int len  );
+
+void *cmatrixalloc (yy_size_t  );
+void *cmatrixrealloc (void *,yy_size_t  );
+void cmatrixfree (void *  );
+
+#define yy_new_buffer cmatrix_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        cmatrixensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            cmatrix_create_buffer(cmatrixin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        cmatrixensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            cmatrix_create_buffer(cmatrixin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define cmatrixwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *cmatrixin = (FILE *) 0, *cmatrixout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int cmatrixlineno;
+
+int cmatrixlineno = 1;
+
+extern char *cmatrixtext;
+#define yytext_ptr cmatrixtext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up cmatrixtext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	cmatrixleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 15
+#define YY_END_OF_BUFFER 16
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_acclist[70] =
+    {   0,
+       16,   15,   15,   14,   15,   15,   15,   15,   15,   15,
+       14,   15,   15,   15,   15,    5,   15,   10,   15,   11,
+       15,   12,   15,   13,   15,    9,   15,    9,   14,   15,
+       15,   15,   15,    7,16392,    6,    5,    5,    5,    7,
+    16392,    5,    5,    5,   10,   11,   12,   13,    9, 8200,
+        5, 8200,    5,    5,    5,    5,    5,    5,    5,    5,
+    16388,    5, 8196,16386,16387, 8194, 8195,16385, 8193
+    } ;
+
+static yyconst flex_int16_t yy_accept[117] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    2,    3,    4,    6,    7,    8,    9,
+       10,   11,   13,   14,   15,   16,   18,   20,   22,   24,
+       26,   28,   31,   32,   33,   34,   34,   36,   36,   36,
+       36,   37,   37,   37,   37,   37,   37,   37,   37,   37,
+       37,   38,   39,   42,   43,   44,   45,   46,   47,   48,
+       49,   50,   50,   50,   50,   50,   50,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51,   51,   53,   54,
+       55,   56,   57,   58,   58,   58,   58,   58,   58,   58,
+       58,   58,   59,   60,   61,   61,   62,   62,   62,   62,
+
+       63,   64,   64,   64,   64,   65,   66,   66,   67,   68,
+       68,   68,   68,   69,   70,   70
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    4,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    1,    1,    6,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    8,    1,    1,
+        1,    1,    1,    1,    1,    1,    9,   10,    1,    1,
+        1,    1,   11,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,   12,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,   13,    1,    1,
+
+       14,    1,    1,    1,   15,    1,    1,   16,    1,   17,
+       18,    1,    1,   19,   20,   21,   22,    1,    1,    1,
+        1,    1,    1,   23,    1,    1,    1,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,
+       24,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   26,   26,   26,   26,   26,   26,   26,
+       26,   26,   26,   26,   26,   26,   26,   26,   26,   27,
+       27,   27,   27,   27,   27,   27,   27,   24,   24,   24,
+       24,   24,   24,   24,   24
+    } ;
+
+static yyconst flex_int32_t yy_meta[28] =
+    {   0,
+        1,    2,    3,    2,    2,    1,    1,    4,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    2,    1,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[143] =
+    {   0,
+        0,  192,   25,   26,   31,   32,   37,   38,   59,   60,
+       82,  108,  197,   43,  678,  678,   31,  128,   32,   35,
+       53,  178,   72,    0,    0,  154,  188,  187,  186,  185,
+       53,   66,  180,    0,    0,  172,   72,   98,    0,    0,
+       92,  203,    0,    0,  103,  108,  107,   76,  136,    0,
+      226,    0,  252,    0,    0,    0,  169,  150,  143,  113,
+      103,  278,    0,    0,  301,    0,  117,  324,    0,    0,
+      347,    0,   83,  131,  133,  119,  159,  370,    0,    0,
+        0,    0,    0,  396,  419,    0,  442,  465,  147,   54,
+      148,    0,    0,    0,  482,  505,  134,  149,  156,    0,
+
+      108,  511,  528,  154,  545,  551,  155,  107,   88,  168,
+      173,  557,  574,   81,  678,  581,  585,  589,   80,  593,
+      597,  601,   58,  605,  609,   46,  613,  617,  621,  625,
+      629,  633,  637,  641,  645,  649,  653,  657,  661,  665,
+      669,  673
+    } ;
+
+static yyconst flex_int16_t yy_def[143] =
+    {   0,
+      115,    1,  116,  116,  116,  116,  116,  116,  116,  116,
+      117,  117,  115,  118,  115,  115,  119,  118,   18,   18,
+       18,   18,  118,  120,  121,  122,  115,  115,  115,  115,
+      123,  123,  123,  124,  125,   18,  126,  118,  120,  121,
+      119,  119,  127,  128,   18,   18,   18,   18,  118,  129,
+      122,  130,  131,  122,  132,  133,  115,  115,  115,  115,
+      123,  123,  124,  125,  123,  134,  126,  126,  135,  136,
+      119,  137,   18,   18,   18,   18,  118,  131,  131,  138,
+      139,  122,  140,  123,  126,  141,  119,   18,   18,   18,
+       18,  131,  142,  122,  126,  115,   18,   18,   18,  131,
+
+      115,   18,   18,   18,  115,  115,   18,  115,  115,   18,
+       18,   18,  115,  115,    0,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115
+    } ;
+
+static yyconst flex_int16_t yy_nxt[706] =
+    {   0,
+       14,   15,   16,   15,   16,   14,   14,   17,   18,   19,
+       20,   21,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   22,   15,   23,   24,   25,   16,   16,   16,
+       16,   27,   27,   16,   16,   16,   16,   28,   28,   16,
+       16,   16,   16,   29,   29,   46,   67,   16,   16,   36,
+       37,   47,   36,   16,   16,   42,   43,   44,   61,   16,
+       16,   16,   16,   16,   16,   30,   30,   38,   39,   40,
+       36,   36,   98,   36,   48,   36,   36,   62,   63,   64,
+       41,   16,   16,   15,   16,   15,   16,  114,   76,   15,
+       62,   63,   64,   36,  109,   36,   68,   69,   70,   36,
+
+       36,   36,   36,   88,   32,   15,   33,   34,   35,   15,
+       16,   15,   16,  108,  101,   15,   42,   43,   44,   60,
+       36,   36,   73,   74,   36,   36,   75,   62,   63,   64,
+       32,   15,   33,   34,   35,   37,   36,   36,   91,   36,
+       36,   68,   69,   70,   89,   45,   90,  102,   36,   59,
+       36,   36,   38,   39,   40,   52,   58,   52,   52,   36,
+       36,   53,   36,   36,   36,   36,   36,   97,   99,  103,
+      104,   36,   36,   36,  107,   57,  110,   52,   54,   55,
+       56,   61,   36,   61,   61,   36,  112,   61,  111,   36,
+       36,   60,   59,   58,   57,   36,  115,   26,  115,  115,
+
+      115,  115,  115,   61,   41,  115,   41,   41,  115,  115,
+       41,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,   41,   52,  115,   52,
+       52,  115,  115,   53,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,   52,
+       54,   55,   56,   52,  115,   52,   52,  115,  115,   52,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,   52,   79,   80,   81,   61,
+      115,   61,   61,  115,  115,   61,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+
+      115,   61,   61,  115,   61,   61,  115,  115,   61,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,   61,   67,  115,   67,   67,  115,
+      115,   67,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,   67,   41,  115,
+       41,   41,  115,  115,   41,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+       41,   52,  115,   52,   52,  115,  115,   52,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,   52,   79,   80,   81,   61,  115,   61,
+
+       61,  115,  115,   61,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,   61,
+       67,  115,   67,   67,  115,  115,   67,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,   67,   41,  115,   41,   41,  115,  115,   41,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,   41,   96,   96,   96,   96,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,   36,   67,  115,   67,   67,  115,  115,   67,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+
+      115,  115,  115,  115,  115,   67,   96,   96,   96,   96,
+      115,  101,  105,  105,  105,  105,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,   36,  106,
+      106,  106,  106,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,   36,  105,  105,  105,  105,
+      115,  108,  106,  106,  106,  106,  115,  109,  113,  113,
+      113,  113,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,   36,  113,  113,  113,  113,  115,
+      114,   15,   15,   15,   15,   31,   31,   31,   31,   36,
+      115,  115,   36,   49,   49,  115,   49,   50,   50,  115,
+
+       50,   51,   51,  115,   51,   65,   65,  115,   65,   66,
+       66,  115,   66,   71,   71,  115,   71,   72,   72,  115,
+       72,   77,   77,  115,   77,   52,   52,  115,   52,   78,
+       78,  115,   78,   82,   82,  115,   82,   83,   83,  115,
+       83,   84,   84,  115,   84,   85,   85,  115,   85,   86,
+       86,  115,   86,   87,   87,  115,   87,   92,   92,  115,
+       92,   93,   93,  115,   93,   94,   94,  115,   94,   95,
+       95,  115,   95,  100,  100,  115,  100,   13,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+
+      115,  115,  115,  115,  115
+    } ;
+
+static yyconst flex_int16_t yy_chk[706] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    3,    4,    3,
+        4,    3,    4,    5,    6,    5,    6,    5,    6,    7,
+        8,    7,    8,    7,    8,   19,  126,    3,    4,   19,
+       14,   20,   20,    5,    6,   17,   17,   17,  123,    7,
+        8,    9,   10,    9,   10,    9,   10,   14,   14,   14,
+       21,   90,   90,   23,   21,   23,   23,   31,   31,   31,
+      119,    9,   10,   11,   11,   11,   11,  114,   48,   11,
+       32,   32,   32,   48,  109,   23,   37,   37,   37,   38,
+
+       73,   38,   38,   73,   11,   11,   11,   11,   11,   12,
+       12,   12,   12,  108,  101,   12,   41,   41,   41,   60,
+       45,   38,   45,   46,   47,   46,   47,   61,   61,   61,
+       12,   12,   12,   12,   12,   18,   76,   49,   76,   49,
+       49,   67,   67,   67,   74,   18,   75,   97,   74,   59,
+       75,   97,   18,   18,   18,   26,   58,   26,   26,   49,
+       77,   26,   77,   77,   89,   91,   98,   89,   91,   98,
+       99,  104,  107,   99,  104,   57,  107,   26,   26,   26,
+       26,   33,   77,   33,   33,  110,  111,   33,  110,   36,
+      111,   30,   29,   28,   27,   22,   13,    2,    0,    0,
+
+        0,    0,    0,   33,   42,    0,   42,   42,    0,    0,
+       42,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   42,   51,    0,   51,
+       51,    0,    0,   51,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   51,
+       51,   51,   51,   53,    0,   53,   53,    0,    0,   53,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   53,   53,   53,   53,   62,
+        0,   62,   62,    0,    0,   62,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,   62,   65,    0,   65,   65,    0,    0,   65,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,   65,   68,    0,   68,   68,    0,
+        0,   68,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   68,   71,    0,
+       71,   71,    0,    0,   71,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       71,   78,    0,   78,   78,    0,    0,   78,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   78,   78,   78,   78,   84,    0,   84,
+
+       84,    0,    0,   84,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   84,
+       85,    0,   85,   85,    0,    0,   85,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   85,   87,    0,   87,   87,    0,    0,   87,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   87,   88,   88,   88,   88,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   88,   95,    0,   95,   95,    0,    0,   95,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,   95,   96,   96,   96,   96,
+        0,   96,  102,  102,  102,  102,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,  102,  103,
+      103,  103,  103,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,  103,  105,  105,  105,  105,
+        0,  105,  106,  106,  106,  106,    0,  106,  112,  112,
+      112,  112,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,  112,  113,  113,  113,  113,    0,
+      113,  116,  116,  116,  116,  117,  117,  117,  117,  118,
+        0,    0,  118,  120,  120,    0,  120,  121,  121,    0,
+
+      121,  122,  122,    0,  122,  124,  124,    0,  124,  125,
+      125,    0,  125,  127,  127,    0,  127,  128,  128,    0,
+      128,  129,  129,    0,  129,  130,  130,    0,  130,  131,
+      131,    0,  131,  132,  132,    0,  132,  133,  133,    0,
+      133,  134,  134,    0,  134,  135,  135,    0,  135,  136,
+      136,    0,  136,  137,  137,    0,  137,  138,  138,    0,
+      138,  139,  139,    0,  139,  140,  140,    0,  140,  141,
+      141,    0,  141,  142,  142,    0,  142,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+
+      115,  115,  115,  115,  115
+    } ;
+
+extern int cmatrix_flex_debug;
+int cmatrix_flex_debug = 0;
+
+static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up cmatrixtext */ \
+yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
+(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
+(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
+yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
+++(yy_lp); \
+goto find_rule; \
+}
+
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *cmatrixtext;
+#line 1 "cmatrix.l"
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2009 Mans Hulden                                     */
+/*     This file is part of foma.                                            */
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+#define YY_NO_INPUT 1
+#line 22 "cmatrix.l"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "foma.h"
+
+extern int cmatrixlex();
+static struct fsm *mnet;
+static int currcost;
+static char *instring;
+
+void my_cmatrixparse(struct fsm *net, char *my_string) {
+   				       
+   YY_BUFFER_STATE my_string_buffer;
+
+   currcost = 1;
+   my_string_buffer = cmatrix_scan_string(my_string);
+   mnet = net;
+   cmatrix_init(mnet);
+   cmatrixlex();
+   cmatrix_delete_buffer(my_string_buffer);
+}
+
+
+#line 737 "lex.cmatrix.c"
+
+#define INITIAL 0
+#define SUB 1
+#define DEL 2
+#define INS 3
+#define COST 4
+#define OUTSTRING 5
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int cmatrixlex_destroy (void );
+
+int cmatrixget_debug (void );
+
+void cmatrixset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE cmatrixget_extra (void );
+
+void cmatrixset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *cmatrixget_in (void );
+
+void cmatrixset_in  (FILE * in_str  );
+
+FILE *cmatrixget_out (void );
+
+void cmatrixset_out  (FILE * out_str  );
+
+int cmatrixget_leng (void );
+
+char *cmatrixget_text (void );
+
+int cmatrixget_lineno (void );
+
+void cmatrixset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cmatrixwrap (void );
+#else
+extern int cmatrixwrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( cmatrixtext, cmatrixleng, 1, cmatrixout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( cmatrixin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( cmatrixin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, cmatrixin))==0 && ferror(cmatrixin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(cmatrixin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cmatrixlex (void);
+
+#define YY_DECL int cmatrixlex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after cmatrixtext and cmatrixleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( cmatrixleng > 0 ) \
+		YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+				(cmatrixtext[cmatrixleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 53 "cmatrix.l"
+
+
+#line 933 "lex.cmatrix.c"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+        /* Create the reject buffer large enough to save one state per allowed character. */
+        if ( ! (yy_state_buf) )
+            (yy_state_buf) = (yy_state_type *)cmatrixalloc(YY_STATE_BUF_SIZE  );
+            if ( ! (yy_state_buf) )
+                YY_FATAL_ERROR( "out of dynamic memory in cmatrixlex()" );
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! cmatrixin )
+			cmatrixin = stdin;
+
+		if ( ! cmatrixout )
+			cmatrixout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			cmatrixensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				cmatrix_create_buffer(cmatrixin,YY_BUF_SIZE );
+		}
+
+		cmatrix_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of cmatrixtext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+		yy_current_state += YY_AT_BOL();
+
+		(yy_state_ptr) = (yy_state_buf);
+		*(yy_state_ptr)++ = yy_current_state;
+
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 116 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			*(yy_state_ptr)++ = yy_current_state;
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 678 );
+
+yy_find_action:
+		yy_current_state = *--(yy_state_ptr);
+		(yy_lp) = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+		for ( ; ; ) /* until we find what rule we matched */
+			{
+			if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
+				{
+				yy_act = yy_acclist[(yy_lp)];
+				if ( yy_act & YY_TRAILING_HEAD_MASK ||
+				     (yy_looking_for_trail_begin) )
+					{
+					if ( yy_act == (yy_looking_for_trail_begin) )
+						{
+						(yy_looking_for_trail_begin) = 0;
+						yy_act &= ~YY_TRAILING_HEAD_MASK;
+						break;
+						}
+					}
+				else if ( yy_act & YY_TRAILING_MASK )
+					{
+					(yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
+					(yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
+					}
+				else
+					{
+					(yy_full_match) = yy_cp;
+					(yy_full_state) = (yy_state_ptr);
+					(yy_full_lp) = (yy_lp);
+					break;
+					}
+				++(yy_lp);
+				goto find_rule;
+				}
+			--yy_cp;
+			yy_current_state = *--(yy_state_ptr);
+			(yy_lp) = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 55 "cmatrix.l"
+{ BEGIN(SUB);  }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 56 "cmatrix.l"
+{ BEGIN(DEL);  }
+	YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 57 "cmatrix.l"
+{ BEGIN(INS);  }
+	YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 58 "cmatrix.l"
+{ BEGIN(COST); }
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 59 "cmatrix.l"
+{ }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 61 "cmatrix.l"
+{
+  cmatrix_set_cost(mnet, NULL, cmatrixtext+1, currcost);
+}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 65 "cmatrix.l"
+{
+  *(cmatrixtext+strlen(cmatrixtext)-1) = '\0';
+  cmatrix_set_cost(mnet, cmatrixtext, NULL, currcost);
+}
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 70 "cmatrix.l"
+{
+  instring = xxstrndup(cmatrixtext, strlen(cmatrixtext)-1);
+  BEGIN(OUTSTRING);
+
+}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 75 "cmatrix.l"
+{
+  cmatrix_set_cost(mnet, instring, cmatrixtext, currcost);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 80 "cmatrix.l"
+{
+  cmatrix_default_substitute(mnet, atoi(cmatrixtext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 84 "cmatrix.l"
+{
+  cmatrix_default_delete(mnet, atoi(cmatrixtext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 88 "cmatrix.l"
+{
+  cmatrix_default_insert(mnet, atoi(cmatrixtext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 93 "cmatrix.l"
+{
+  currcost = atoi(cmatrixtext);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 14:
+/* rule 14 can match eol */
+YY_RULE_SETUP
+#line 98 "cmatrix.l"
+{ }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 99 "cmatrix.l"
+ECHO;
+	YY_BREAK
+#line 1150 "lex.cmatrix.c"
+			case YY_STATE_EOF(INITIAL):
+			case YY_STATE_EOF(SUB):
+			case YY_STATE_EOF(DEL):
+			case YY_STATE_EOF(INS):
+			case YY_STATE_EOF(COST):
+			case YY_STATE_EOF(OUTSTRING):
+				yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed cmatrixin at a new source and called
+			 * cmatrixlex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = cmatrixin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( cmatrixwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * cmatrixtext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of cmatrixlex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			cmatrixrestart(cmatrixin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cmatrixrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+	yy_current_state += YY_AT_BOL();
+
+	(yy_state_ptr) = (yy_state_buf);
+	*(yy_state_ptr)++ = yy_current_state;
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 24);
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 116 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		*(yy_state_ptr)++ = yy_current_state;
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	register YY_CHAR yy_c = 24;
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 116 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 115);
+	if ( ! yy_is_jam )
+		*(yy_state_ptr)++ = yy_current_state;
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					cmatrixrestart(cmatrixin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( cmatrixwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve cmatrixtext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void cmatrixrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        cmatrixensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            cmatrix_create_buffer(cmatrixin,YY_BUF_SIZE );
+	}
+
+	cmatrix_init_buffer(YY_CURRENT_BUFFER,input_file );
+	cmatrix_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+    void cmatrix_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		cmatrixpop_buffer_state();
+	 *		cmatrixpush_buffer_state(new_buffer);
+     */
+	cmatrixensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	cmatrix_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (cmatrixwrap()) processing, but the only time this flag
+	 * is looked at is after cmatrixwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void cmatrix_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	cmatrixin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE cmatrix_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) cmatrixalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in cmatrix_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) cmatrixalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in cmatrix_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	cmatrix_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cmatrix_create_buffer()
+ *
+ */
+    void cmatrix_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		cmatrixfree((void *) b->yy_ch_buf  );
+
+	cmatrixfree((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cmatrixrestart() or at EOF.
+ */
+    static void cmatrix_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	cmatrix_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then cmatrix_init_buffer was _probably_
+     * called from cmatrixrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+    void cmatrix_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		cmatrix_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *
+ */
+void cmatrixpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	cmatrixensure_buffer_stack();
+
+	/* This block is copied from cmatrix_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from cmatrix_switch_to_buffer. */
+	cmatrix_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *
+ */
+void cmatrixpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	cmatrix_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		cmatrix_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void cmatrixensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)cmatrixalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in cmatrixensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)cmatrixrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in cmatrixensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmatrix_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) cmatrixalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in cmatrix_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	cmatrix_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cmatrixlex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       cmatrix_scan_bytes() instead.
+ */
+YY_BUFFER_STATE cmatrix_scan_string (yyconst char * yystr )
+{
+    
+	return cmatrix_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cmatrixlex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cmatrix_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) cmatrixalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in cmatrix_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = cmatrix_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in cmatrix_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up cmatrixtext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		cmatrixtext[cmatrixleng] = (yy_hold_char); \
+		(yy_c_buf_p) = cmatrixtext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		cmatrixleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int cmatrixget_lineno  (void)
+{
+        
+    return cmatrixlineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *cmatrixget_in  (void)
+{
+        return cmatrixin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *cmatrixget_out  (void)
+{
+        return cmatrixout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int cmatrixget_leng  (void)
+{
+        return cmatrixleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *cmatrixget_text  (void)
+{
+        return cmatrixtext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void cmatrixset_lineno (int  line_number )
+{
+    
+    cmatrixlineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see cmatrix_switch_to_buffer
+ */
+void cmatrixset_in (FILE *  in_str )
+{
+        cmatrixin = in_str ;
+}
+
+void cmatrixset_out (FILE *  out_str )
+{
+        cmatrixout = out_str ;
+}
+
+int cmatrixget_debug  (void)
+{
+        return cmatrix_flex_debug;
+}
+
+void cmatrixset_debug (int  bdebug )
+{
+        cmatrix_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from cmatrixlex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+    (yy_state_buf) = 0;
+    (yy_state_ptr) = 0;
+    (yy_full_match) = 0;
+    (yy_lp) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    cmatrixin = stdin;
+    cmatrixout = stdout;
+#else
+    cmatrixin = (FILE *) 0;
+    cmatrixout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * cmatrixlex_init()
+     */
+    return 0;
+}
+
+/* cmatrixlex_destroy is for both reentrant and non-reentrant scanners. */
+int cmatrixlex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		cmatrix_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		cmatrixpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	cmatrixfree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    cmatrixfree ( (yy_state_buf) );
+    (yy_state_buf)  = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * cmatrixlex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *cmatrixalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *cmatrixrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void cmatrixfree (void * ptr )
+{
+	free( (char *) ptr );	/* see cmatrixrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 99 "cmatrix.l"
diff --git a/back-ends/foma/cpp-version/lex.interface.cc b/back-ends/foma/cpp-version/lex.interface.cc
new file mode 100644
index 0000000..820afaa
--- /dev/null
+++ b/back-ends/foma/cpp-version/lex.interface.cc
@@ -0,0 +1,10632 @@
+#line 23 "interface.l"
+#define YY_BUF_SIZE 1048576
+
+
+
+#line 7 "lex.interface.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer interface_create_buffer
+#define yy_delete_buffer interface_delete_buffer
+#define yy_flex_debug interface_flex_debug
+#define yy_init_buffer interface_init_buffer
+#define yy_flush_buffer interface_flush_buffer
+#define yy_load_buffer_state interface_load_buffer_state
+#define yy_switch_to_buffer interface_switch_to_buffer
+#define yyin interfacein
+#define yyleng interfaceleng
+#define yylex interfacelex
+#define yylineno interfacelineno
+#define yyout interfaceout
+#define yyrestart interfacerestart
+#define yytext interfacetext
+#define yywrap interfacewrap
+#define yyalloc interfacealloc
+#define yyrealloc interfacerealloc
+#define yyfree interfacefree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE interfacerestart(interfacein  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int interfaceleng;
+
+extern FILE *interfacein, *interfaceout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+     *       access to the local variable yy_act. Since yyless() is a macro, it would break
+     *       existing scanners that call yyless() from OUTSIDE interfacelex. 
+     *       One obvious solution it to make yy_act a global. I tried that, and saw
+     *       a 5% performance hit in a non-interfacelineno scanner, because yy_act is
+     *       normally declared as a register variable-- so it is not worth it.
+     */
+    #define  YY_LESS_LINENO(n) \
+            do { \
+                int yyl;\
+                for ( yyl = n; yyl < interfaceleng; ++yyl )\
+                    if ( interfacetext[yyl] == '\n' )\
+                        --interfacelineno;\
+            }while(0)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up interfacetext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up interfacetext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via interfacerestart()), so that the user can continue scanning by
+	 * just pointing interfacein at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when interfacetext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int interfaceleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow interfacewrap()'s to do buffer switches
+ * instead of setting up a fresh interfacein.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void interfacerestart (FILE *input_file  );
+void interface_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE interface_create_buffer (FILE *file,int size  );
+void interface_delete_buffer (YY_BUFFER_STATE b  );
+void interface_flush_buffer (YY_BUFFER_STATE b  );
+void interfacepush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void interfacepop_buffer_state (void );
+
+static void interfaceensure_buffer_stack (void );
+static void interface_load_buffer_state (void );
+static void interface_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER interface_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE interface_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE interface_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE interface_scan_bytes (yyconst char *bytes,int len  );
+
+void *interfacealloc (yy_size_t  );
+void *interfacerealloc (void *,yy_size_t  );
+void interfacefree (void *  );
+
+#define yy_new_buffer interface_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        interfaceensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            interface_create_buffer(interfacein,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        interfaceensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            interface_create_buffer(interfacein,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define interfacewrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *interfacein = (FILE *) 0, *interfaceout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int interfacelineno;
+
+int interfacelineno = 1;
+
+extern char *interfacetext;
+#define yytext_ptr interfacetext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up interfacetext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	(yytext_ptr) -= (yy_more_len); \
+	interfaceleng = (size_t) (yy_cp - (yytext_ptr)); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 212
+#define YY_END_OF_BUFFER 213
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_acclist[1635] =
+    {   0,
+      211,  211,  152,  152,  213,  210,  212,  207,  210,  212,
+      208,  210,  212,  207,  209,  210,  212,  181,  207,  210,
+      212,  142,  212,  210,  212,  207,  210,  212,  208,  210,
+      212,  207,  209,  210,  212,  181,  207,  210,  212,  210,
+      212,  210,  212,  210,  212,  210,  212,  210,  212,  210,
+      212,  210,  212,  210,  212,  210,  212,  210,  212,  210,
+      212,  210,  212,  210,  212,  210,  212,  210,  212,  210,
+      212,  210,  212,  210,  212,  210,  212,  210,  212,  210,
+      212,  210,  212,  210,  212,  210,  212,  144,  212,  144,
+      208,  212,  144,  209,  212,  144,  181,  212,  141,  212,
+
+      151,  212,  212,  144,  212,  147,  212,  148,  212,  212,
+      212,  212,  212,  167,  212,16550,  208,  212,  167,  209,
+      212,16550,  181,  212,  212,  212,  212,  212,  208,  212,
+      209,  212,  177,  212,  177,  181,  212,  212,  212,  212,
+      132,  133,  212,  132,  133,  181,  212,  212,  212,  212,
+      129,  212,  129,  208,  212,  129,  209,  212,  129,  181,
+      212,  212,  129,  212,  129,  212,  129,  212,  129,  212,
+      134,  212,  134,  181,  212,  212,  212,  212,  135,  212,
+      135,  181,  212,  212,  212,  212,  140,  212,  140,  181,
+      212,  212,  212,  212,  198,  212,  181,  198,  212,  212,
+
+      212,  212,  168,  212,  168,  181,  212,  212,  212,  212,
+      203,  212,  181,  203,  212,  212,  212,  212,  204,  212,
+      181,  204,  212,  212,  212,  212,  206,  212,  181,  206,
+      212,  212,  212,  212,  183,  212,  181,  183,  212,  212,
+      212,  212,  182,  212,  181,  182,  212,  212,  212,  212,
+      178,  212,  178,  181,  212,  212,  212,  212,  179,  212,
+      179,  208,  212,  179,  209,  212,  180,  212,  180,  209,
+      212,  189,  212,  181,  189,  212,  212,  212,  212,  188,
+      212,  181,  188,  212,  212,  212,  212,  190,  212,  181,
+      190,  212,  212,  212,  212,  191,  212,  181,  191,  212,
+
+      212,  212,  212,  211,  212,  209,  211,  212,  181,  211,
+      212,  152,  212,  152,  208,  212,  152,  209,  212,  152,
+      181,  212,  153,  212,  149,  212,  149,  208,  212,  149,
+      209,  212,  149,  181,  212,  150,  212,  139,  212,  139,
+      181,  212,  212,  212,  212,  136,  212,  136,  181,  212,
+      212,  212,  212,  200,  212,  181,  200,  212,  212,  212,
+      212,  199,  212,  181,  199,  212,  212,  212,  212,  155,
+      212,  212,16541,16542,  208,  212,16541,16542,  209,  212,
+    16541,16542,  156,  181,  212,  159,  212,  165,  212,  165,
+      209,  212,  165,  181,  212,  165,  212,  165,  212,  160,
+
+      165,  212,  165,  212,  164,  165,  212,  165,  212,  165,
+      212,  165,  212,  165,  212,  165,  212,  165,  212,  165,
+      212,  165,  212,  165,  212,  165,  212,  165,  212,  138,
+      212,  138,  181,  212,  212,  212,  212,  137,  212,  137,
+      181,  212,  212,  212,  212,  169,  212,  169,  181,  212,
+      212,  212,  212,  170,  212,  170,  181,  212,  212,  212,
+      212,  171,  212,  171,  208,  212,  171,  209,  212,  173,
+      212,  172,  212,  173,  208,  212,  173,  209,  212,  172,
+      181,  212,  176,  212,  176,  181,  212,  212,  212,  212,
+      192,  212,  192,  208,  212,  192,  209,  212,  212,  194,
+
+      212,  181,  194,  212,  212,  212,  212,  195,  212,  195,
+      208,  212,  195,  209,  212,  212,  197,  212,  181,  197,
+      212,  212,  212,  212,  174,  212,  174,  181,  212,  212,
+      212,  212,  175,  212,  175,  181,  212,  212,  212,  212,
+      146,  212,  145,  146,  208,  212,  146,  209,  212,  146,
+      181,  212,  212,  212,  212,  130,  212,  131,  212,  131,
+      181,  212,  212,  212,  212,  202,  212,  181,  202,  212,
+      212,  212,  212,  205,  212,  181,  205,  212,  212,  212,
+      212,  201,  212,  181,  201,  212,  212,  212,  212,  184,
+      212,  181,  184,  212,  212,  212,  212,  185,  212,  181,
+
+      185,  212,  212,  212,  212,  186,  212,  181,  186,  212,
+      212,  212,  212,  187,  212,  181,  187,  212,  212,  212,
+      212,  142,   20,   55,   46,   47,   82,  103,  117,    8,
+      127,  144,  143,  144,  167,16550, 8358,  167,  154,  167,
+      177,  132,  133,  129,  129,  128,  129,  129,  129,  129,
+      129,  134,  135,  140,  198,  168,  203,  204,  206,  183,
+      182,  178,  179,  180,  189,  188,  190,  191,  152,  139,
+      136,  200,  199,16541,16542, 8350, 8349,  159,  162,  160,
+      138,  137,  169,  170,  171,  173,  176,  192,  194,  195,
+      197,  174,  175,  146,  130,  131,  202,  205,  201,  184,
+
+      185,  186,  187,   47,   84,  125,   83,   48,   19,   19,
+       49,   21,   50,  109,   30,   37,   53,    5,   43,   44,
+       44,   55,   45,   56,   46,   47,   81,   79,   80,   82,
+       82,   82,   89,   89,   92,   93,   87,   31,   99,   66,
+       67,  103,   95,   95,  107,  107,  118,  110,  111,  114,
+      112,  113,  117,  116,  120,    7,    8,    8,    7,    7,
+        9,    7,   20,    7,   69,    7,    7,    7,  123,  127,
+      167,  129,  163,  163,  163,  163,  165,  161,  161,  161,
+      161,  160,   47,   84,  125,   84,  125,   84,   48,   17,
+       49,   21,   50,   50,    3,   23,   30,   30,   33,   37,
+
+       88,   77,   53,    6,    5,    5,    6,    6,   20,    6,
+        6,    6,   55,   45,   56,16443,   56,16443,   46,   87,
+       81,   82,   84,   89,   89,   92,   93,   87,   87,   87,
+       31,   31,16480,   99,   66,   67,  103,  104,  104,   95,
+       95,   95,   95,   91,  115,  117,  119,  119,  120,    7,
+        9,    9,   78,   69,  122,  125,  123,  123,  127,  163,
+      163,  163,  163,  163,  163,  163,  161,  161,  161,  161,
+      161,  161,  161,  193,  196,   10,   10,   10,   10,   20,
+       10,   10,   10,   10,  126,   84,  125,  126,   84,  125,
+      126,   84,  126,   20,  126,  126,  126,  126,   84,  125,
+
+      126,   84,  126,   84,   84,   12,   13,   48,   15,   16,
+       17,   18,   49,   21,   52,   50,   52,   52,   20,   52,
+       52,   52,   52,   50,   52,   51,   51,   51,   20,   51,
+       51,   51,   51,    2,    3,    3,    2,    4,    2,   20,
+        2,    2,    2,   22,   22,   28,   33,   33,   35,   37,
+       88,   88,   88,   41,   41,   54,   54,   77,   77,   77,
+       53,   45,   58,   58,   20,   58,   58,   58,   58,   57,
+       57,   57,   20,   57,   57,   57,   57,   46,   46,   46,
+       71,   55,   55,   87,   87,   87,   87,   81,   84,   84,
+       84,   92,   93,   87,   87,   87,   20,   99,   66,  101,
+
+      103,  101,  103,   95,   95,   95,   91,   91,   91,  117,
+      117,  108,  120,    9,   70,   70,   78,   78,   78,   69,
+      125,  125,   73,  124,  123,  124,  123,  124,   20,  124,
+      124,  124,  124,  123,  124,  127,  127,  127,  163,  163,
+      163,  163,  163,  163,  161,  161,  161,  161,  161,  161,
+      126,   84,  126,   48,   15,   16,   17,   18,   49,   21,
+       21,   21,   51,   51,    4,    4,   28,   28,   34,   33,
+       34,   34,   20,   34,   34,   34,   34,   34,   34,   33,
+       34,   34,   34,   35,   37,   37,   37,   88,   88,   88,
+       41,   41,   40,   40,   77,   53,   43,   43,   44,   44,
+
+       44,   45,   45,   45,   57,   57,   46,   46,   46,   76,
+       47,   47,   48,   49,   53,   55,   66,   69,   48,   49,
+       50,   53,   55,   56,   66,   67,   69,   87,   87,   87,
+       87,  123,   81,   81,   82,   82,   84,   84,   84,   84,
+       84,   89,   92,   92,   92,   93,   93,   93,   87,   94,
+       94,   98,   98,   98,   20,   98,   98,   98,   98,   98,
+       98,   98,   99,   99,   99,  103,  102,  103,  102,   91,
+       91,   91,  117,  117,  120,  120,   78,   69,  125,  126,
+      125,  125,  126,   75,  124,  124,  125,  127,  127,  127,
+      126,   48,   85,   15,   16,   17,   17,   17,   18,   49,
+
+       21,   21,   21,    4,   29,   37,   37,   88,   32,   40,
+       40,   53,   43,   43,   45,   45, 8251, 8251, 8251,   20,
+     8251, 8251, 8251, 8251, 8251, 8251, 8251, 8251,   46,   76,
+       76,   76,   47,   47,   48,   49,   53,   55,   66,   69,
+       48,   49,   50,   53,   55,   56,16443,   66,   67,   69,
+       87,   87,  123,   87,  123,   81,   81,   82,   82,   82,
+       82,   82,   84,   84,   84,   87,   84,   84,   88,   87,
+       91,   92,   92,   92,   93,   93,   94,   94,   94,   94,
+     8288, 8288,   20, 8288,   99,   99,   99,   91,  117,  117,
+      120,  120,   69,  122,  122,   74,   74,   75,   75,   75,
+
+      124,  125,  127,    8,    8,   12,   12,   13,   13,   86,
+       85,   85,   86,   86,   20,   86,   86,   86,   86,   15,
+       15,   15,   16,   16,   17,   17,   17,   18,   18,   18,
+       21,   29,   29,   35,   35,   53,   43, 8251,   46,   76,
+       47,   47,   48,   49,   53,   66,   69,   48,   49,   50,
+       52,   53,   71,   66,   69,   73,   87,  123,  124,   87,
+      123,   87,  124,   87,  123,  124,   87,  124,   82,   82,
+       87,   88,   87,   87,   91,   93,   93,   94,   94,   94,
+       98,   98,   97,   98,   97,  101,  101,  105,  105,  106,
+      106,  105,  106,  117,  117,   69,  122,  122,   75,  125,
+
+      126,  125,  127,    1,    5,    8,   83,   12,   12,   13,
+       13,   86,   14,   14,   15,   15,   16,   16,   17,   18,
+       18,   18,   21,   30,   35,   35,   36,   38,   38,   53,
+       47,   47,   48,   49,   53,   69,   48,   49,   53,   69,
+       82,   82,   87,   87,   93,   93,   97,   97,  100,  100,
+      102,  102,   68,  113,   69,  123,  127,    1,    1,    3,
+        5,   12,   12,   13,   13,   14,   14,   17,   18,   21,
+       38,   38,   38,   41,   41,   42,   53,   48,   48,   49,
+       53,   69,   82,   82,   85,   85,   95,   95,   97,   97,
+      100,  100,  100,   68,  121,   69,  123,    3,   12,   12,
+
+       13,   13,   14,   14,   17,   18,   21,   41,   41,   41,
+       53,   53,   69,   85,   95,   95,   95,   97,   97,   90,
+       69,  123,  124,  123,   18,   32,   36,   36,   53,   68,
+       69,   60,   72,   62,   64,   97,   97,   90,   90,   90,
+      121,  121,   11,   11,   36,   36,   40,   40,   40,   42,
+       42,   53,   68,   69,   94,   94,   94,   31,   97,   97,
+       90,   90,   90,  111,  112,  121,  121,   26,   26,   39,
+       39,   40,   40,   40,   42,   42,   53,   69,   61,   61,
+       63,   63,   65,   65,   90,   94,   94,   94,   97,   97,
+       90,  121,  121,    1,    1,   25,   25,   24,   25,   24,
+
+       27,   27,   20,   27,   27,   27,   27,   27,   27,   39,
+       39,   39,   60,   72,   62,   64,   90,   79,  109,  110,
+      115,    1,    1,    1,  108,   28,   28,   79,   29,  116,
+       29,  114,   80,  118
+    } ;
+
+static yyconst flex_int16_t yy_accept[2917] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,
+        3,    4,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    6,    8,   11,   14,   18,   22,   24,
+       26,   29,   32,   36,   40,   42,   44,   46,   48,   50,
+       52,   54,   56,   58,   60,   62,   64,   66,   68,   70,
+       72,   74,   76,   78,   80,   82,   84,   86,   88,   90,
+       93,   96,   99,  101,  103,  104,  106,  108,  110,  111,
+      112,  113,  114,  117,  119,  123,  125,  126,  127,  128,
+      129,  131,  133,  135,  138,  139,  140,  141,  144,  148,
+      149,  150,  151,  153,  156,  159,  162,  163,  165,  167,
+
+      169,  171,  173,  176,  177,  178,  179,  181,  184,  185,
+      186,  187,  189,  192,  193,  194,  195,  197,  200,  201,
+      202,  203,  205,  208,  209,  210,  211,  213,  216,  217,
+      218,  219,  221,  224,  225,  226,  227,  229,  232,  233,
+      234,  235,  237,  240,  241,  242,  243,  245,  248,  249,
+      250,  251,  253,  256,  257,  258,  259,  261,  264,  267,
+      269,  272,  274,  277,  278,  279,  280,  282,  285,  286,
+      287,  288,  290,  293,  294,  295,  296,  298,  301,  302,
+      303,  304,  306,  309,  312,  314,  317,  320,  323,  325,
+      327,  330,  333,  336,  338,  340,  343,  344,  345,  346,
+
+      348,  351,  352,  353,  354,  356,  359,  360,  361,  362,
+      364,  367,  368,  369,  370,  372,  375,  379,  383,  386,
+      388,  390,  393,  396,  398,  400,  403,  405,  408,  410,
+      412,  414,  416,  418,  420,  422,  424,  426,  428,  430,
+      432,  435,  436,  437,  438,  440,  443,  444,  445,  446,
+      448,  451,  452,  453,  454,  456,  459,  460,  461,  462,
+      464,  467,  470,  472,  474,  477,  480,  483,  485,  488,
+      489,  490,  491,  493,  496,  499,  500,  502,  505,  506,
+      507,  508,  510,  513,  516,  517,  519,  522,  523,  524,
+      525,  527,  530,  531,  532,  533,  535,  538,  539,  540,
+
+      541,  543,  547,  550,  553,  554,  555,  556,  558,  560,
+      563,  564,  565,  566,  568,  571,  572,  573,  574,  576,
+      579,  580,  581,  582,  584,  587,  588,  589,  590,  592,
+      595,  596,  597,  598,  600,  603,  604,  605,  606,  608,
+      611,  612,  613,  614,  616,  619,  620,  621,  622,  623,
+      623,  623,  623,  624,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  625,  625,  626,  626,  627,  627,  627,  628,  628,
+      628,  628,  628,  628,  628,  628,  628,  628,  629,  629,
+      629,  629,  629,  629,  629,  629,  629,  629,  629,  629,
+      630,  630,  630,  631,  631,  631,  631,  631,  631,  632,
+      632,  632,  633,  633,  633,  633,  634,  635,  635,  635,
+      637,  639,  639,  640,  641,  641,  641,  641,  641,  641,
+      642,  642,  642,  642,  642,  642,  644,  644,  644,  644,
+      644,  644,  645,  646,  647,  648,  649,  650,  650,  650,
+      650,  650,  651,  651,  652,  652,  653,  653,  653,  653,
+
+      653,  653,  654,  654,  654,  654,  654,  654,  655,  655,
+      655,  655,  655,  655,  656,  656,  656,  656,  656,  656,
+      657,  657,  657,  657,  657,  657,  658,  658,  658,  658,
+      658,  658,  659,  659,  659,  659,  659,  659,  660,  660,
+      660,  660,  660,  660,  661,  661,  661,  661,  661,  661,
+      662,  662,  662,  662,  662,  662,  663,  663,  663,  663,
+      663,  663,  664,  665,  666,  666,  666,  666,  666,  666,
+      667,  667,  667,  667,  667,  667,  668,  668,  668,  668,
+      668,  668,  669,  669,  669,  669,  669,  669,  670,  671,
+      671,  671,  671,  671,  671,  672,  672,  672,  672,  672,
+
+      672,  673,  673,  673,  673,  673,  673,  674,  674,  674,
+      674,  674,  674,  676,  676,  677,  678,  679,  679,  679,
+      679,  679,  680,  680,  680,  680,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  682,  682,  682,  682,  682,  682,  683,
+      683,  683,  683,  683,  683,  684,  684,  684,  684,  684,
+      684,  685,  685,  685,  685,  685,  685,  686,  687,  688,
+      688,  688,  688,  688,  688,  689,  689,  690,  690,  690,
+      690,  690,  690,  691,  691,  692,  692,  692,  692,  692,
+
+      692,  693,  693,  693,  693,  693,  693,  694,  694,  694,
+      694,  694,  694,  695,  695,  695,  696,  697,  697,  697,
+      697,  697,  697,  698,  698,  698,  698,  698,  698,  699,
+      699,  699,  699,  699,  699,  700,  700,  700,  701,  701,
+      701,  701,  701,  701,  702,  702,  702,  702,  702,  702,
+      703,  703,  703,  703,  703,  703,  704,  704,  704,  704,
+      704,  704,  705,  705,  705,  705,  705,  705,  707,  707,
+      707,  708,  708,  708,  709,  709,  709,  709,  710,  711,
+      712,  713,  714,  714,  714,  714,  715,  715,  715,  715,
+      715,  715,  716,  716,  716,  716,  716,  716,  717,  717,
+
+      717,  717,  717,  717,  718,  719,  720,  721,  722,  723,
+      724,  725,  725,  725,  726,  726,  727,  727,  727,  727,
+      727,  728,  729,  730,  731,  732,  733,  733,  733,  733,
+      734,  735,  735,  735,  736,  737,  738,  738,  739,  739,
+      739,  740,  741,  742,  742,  742,  743,  743,  743,  744,
+      745,  745,  745,  746,  747,  747,  747,  747,  748,  749,
+      750,  751,  752,  753,  753,  753,  753,  753,  754,  755,
+      755,  755,  756,  757,  758,  759,  760,  762,  764,  766,
+      767,  768,  769,  769,  769,  769,  769,  770,  770,  770,
+      770,  770,  770,  771,  771,  771,  771,  771,  772,  772,
+
+      772,  772,  773,  773,  773,  773,  773,  773,  773,  773,
+      773,  773,  773,  773,  773,  773,  773,  773,  773,  773,
+      773,  773,  773,  774,  774,  775,  775,  775,  775,  775,
+      776,  776,  776,  776,  776,  777,  777,  777,  777,  777,
+      777,  778,  779,  779,  780,  780,  780,  780,  780,  781,
+      781,  781,  781,  781,  782,  782,  782,  782,  783,  783,
+      783,  783,  783,  783,  783,  783,  783,  783,  783,  783,
+      783,  783,  783,  783,  783,  783,  783,  783,  783,  783,
+      783,  784,  784,  784,  784,  784,  784,  784,  786,  788,
+      789,  789,  789,  789,  789,  790,  790,  791,  791,  792,
+
+      792,  792,  793,  794,  795,  795,  796,  797,  797,  797,
+      797,  797,  797,  798,  799,  799,  800,  800,  800,  800,
+      800,  800,  801,  801,  801,  802,  802,  802,  802,  802,
+      803,  804,  805,  806,  807,  808,  810,  811,  812,  813,
+      813,  813,  813,  813,  813,  814,  814,  814,  815,  817,
+      819,  819,  819,  819,  820,  820,  820,  820,  820,  820,
+      820,  820,  820,  820,  820,  820,  820,  820,  820,  820,
+      820,  820,  820,  820,  820,  820,  820,  821,  821,  821,
+      822,  822,  822,  823,  823,  824,  824,  824,  824,  824,
+      824,  824,  824,  824,  824,  824,  824,  824,  824,  824,
+
+      824,  824,  824,  825,  826,  826,  826,  826,  827,  827,
+      827,  828,  829,  830,  831,  831,  832,  833,  833,  834,
+      834,  834,  834,  834,  835,  836,  837,  837,  837,  837,
+      837,  837,  837,  838,  839,  840,  840,  840,  841,  842,
+      843,  844,  844,  844,  844,  844,  844,  844,  845,  846,
+      846,  846,  846,  847,  847,  848,  849,  849,  849,  849,
+      850,  852,  853,  853,  853,  854,  855,  856,  856,  857,
+      857,  858,  859,  859,  859,  859,  859,  859,  859,  859,
+      860,  860,  860,  861,  861,  861,  861,  861,  862,  862,
+      862,  862,  862,  863,  863,  863,  863,  863,  864,  864,
+
+      864,  864,  864,  864,  865,  865,  865,  865,  865,  866,
+      866,  866,  866,  866,  867,  867,  867,  867,  867,  867,
+      868,  868,  868,  868,  868,  869,  869,  869,  869,  869,
+      870,  870,  870,  870,  870,  871,  871,  871,  871,  871,
+      871,  872,  872,  872,  872,  872,  873,  873,  873,  873,
+      873,  874,  874,  874,  874,  874,  875,  876,  876,  876,
+      877,  878,  879,  881,  882,  883,  884,  885,  885,  885,
+      886,  889,  891,  892,  894,  896,  896,  897,  898,  899,
+      902,  904,  904,  905,  906,  906,  906,  907,  908,  909,
+      909,  910,  911,  911,  911,  912,  913,  914,  914,  914,
+
+      915,  916,  918,  919,  921,  922,  923,  924,  926,  926,
+      927,  928,  928,  929,  931,  932,  933,  934,  935,  936,
+      937,  938,  939,  941,  942,  943,  944,  945,  946,  946,
+      947,  947,  947,  947,  947,  948,  949,  949,  950,  950,
+      950,  950,  951,  951,  951,  952,  953,  954,  954,  955,
+      956,  956,  957,  958,  959,  960,  961,  962,  962,  962,
+      962,  962,  962,  962,  962,  963,  964,  965,  967,  968,
+      969,  970,  970,  971,  972,  972,  973,  975,  976,  977,
+      978,  979,  980,  981,  982,  982,  982,  982,  982,  982,
+      982,  983,  983,  983,  983,  983,  983,  983,  983,  983,
+
+      984,  984,  984,  984,  984,  984,  984,  984,  984,  984,
+      985,  986,  987,  988,  988,  988,  989,  989,  989,  989,
+      990,  991,  992,  992,  992,  992,  992,  992,  992,  992,
+      992,  992,  992,  992,  992,  992,  992,  992,  992,  993,
+      993,  993,  994,  995,  996,  997,  997,  997,  997,  997,
+      997,  997,  998,  998,  998,  998,  998,  998,  999, 1000,
+     1001, 1002, 1002, 1003, 1004, 1004, 1004, 1004, 1005, 1006,
+     1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007,
+     1008, 1009, 1010, 1011, 1012, 1013, 1013, 1013, 1013, 1013,
+     1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1021, 1021,
+
+     1021, 1022, 1023, 1024, 1025, 1027, 1028, 1029, 1031, 1031,
+     1032, 1033, 1034, 1036, 1036, 1036, 1036, 1036, 1036, 1036,
+     1037, 1038, 1039, 1039, 1040, 1040, 1040, 1040, 1040, 1041,
+     1041, 1041, 1041, 1041, 1042, 1042, 1042, 1042, 1042, 1043,
+     1043, 1043, 1043, 1043, 1044, 1044, 1044, 1044, 1044, 1045,
+     1045, 1045, 1045, 1045, 1046, 1046, 1046, 1046, 1046, 1047,
+     1047, 1047, 1047, 1047, 1048, 1048, 1048, 1048, 1048, 1049,
+     1049, 1049, 1049, 1049, 1050, 1050, 1050, 1050, 1050, 1051,
+     1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1052,
+     1052, 1053, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054,
+
+     1055, 1055, 1055, 1055, 1055, 1055, 1056, 1056, 1056, 1057,
+     1057, 1057, 1058, 1058, 1058, 1059, 1060, 1061, 1062, 1063,
+     1064, 1064, 1065, 1066, 1067, 1067, 1068, 1069, 1069, 1069,
+     1069, 1069, 1070, 1072, 1073, 1075, 1076, 1077, 1078, 1079,
+     1080, 1082, 1083, 1084, 1084, 1084, 1084, 1085, 1085, 1086,
+     1087, 1088, 1088, 1088, 1088, 1089, 1090, 1091, 1091, 1092,
+     1093, 1093, 1093, 1093, 1093, 1094, 1095, 1096, 1096, 1096,
+     1097, 1098, 1099, 1099, 1100, 1101, 1101, 1102, 1102, 1103,
+     1104, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1106, 1106, 1107, 1108, 1109, 1110, 1110, 1110,
+
+     1111, 1112, 1113, 1114, 1115, 1116, 1117, 1117, 1118, 1119,
+     1120, 1121, 1122, 1123, 1124, 1125, 1125, 1125, 1125, 1126,
+     1127, 1127, 1128, 1128, 1129, 1130, 1131, 1133, 1134, 1135,
+     1136, 1137, 1137, 1138, 1139, 1140, 1141, 1141, 1141, 1142,
+     1142, 1142, 1142, 1143, 1143, 1143, 1143, 1144, 1145, 1146,
+     1147, 1148, 1149, 1150, 1150, 1150, 1150, 1150, 1151, 1152,
+     1152, 1152, 1152, 1152, 1153, 1154, 1155, 1157, 1158, 1159,
+     1160, 1161, 1162, 1163, 1164, 1165, 1166, 1166, 1166, 1166,
+     1167, 1168, 1168, 1169, 1170, 1170, 1170, 1170, 1170, 1170,
+     1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170,
+
+     1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1171, 1172,
+     1173, 1174, 1175, 1175, 1175, 1176, 1177, 1178, 1178, 1178,
+     1179, 1179, 1179, 1179, 1181, 1182, 1184, 1184, 1184, 1185,
+     1186, 1186, 1187, 1187, 1187, 1188, 1188, 1189, 1190, 1191,
+     1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1192,
+     1192, 1192, 1192, 1192, 1192, 1192, 1194, 1194, 1194, 1194,
+     1194, 1194, 1195, 1195, 1195, 1196, 1197, 1198, 1199, 1199,
+     1199, 1200, 1201, 1202, 1203, 1204, 1205, 1205, 1205, 1205,
+     1205, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1207,
+     1208, 1208, 1208, 1208, 1208, 1209, 1210, 1210, 1210, 1210,
+
+     1210, 1211, 1212, 1212, 1213, 1214, 1215, 1215, 1216, 1217,
+     1218, 1219, 1219, 1220, 1222, 1223, 1224, 1225, 1226, 1226,
+     1227, 1227, 1227, 1227, 1228, 1229, 1229, 1230, 1231, 1232,
+     1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242,
+     1243, 1244, 1244, 1245, 1246, 1248, 1248, 1248, 1248, 1249,
+     1250, 1250, 1250, 1251, 1251, 1252, 1254, 1256, 1257, 1258,
+     1259, 1260, 1261, 1262, 1263, 1263, 1264, 1265, 1266, 1266,
+     1267, 1268, 1269, 1269, 1270, 1271, 1271, 1271, 1272, 1273,
+     1274, 1275, 1276, 1277, 1277, 1277, 1277, 1277, 1278, 1279,
+     1280, 1281, 1281, 1282, 1283, 1285, 1285, 1285, 1285, 1285,
+
+     1285, 1285, 1286, 1287, 1288, 1288, 1288, 1288, 1288, 1288,
+     1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288,
+     1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288,
+     1288, 1288, 1288, 1288, 1288, 1288, 1289, 1290, 1291, 1291,
+     1291, 1292, 1293, 1293, 1294, 1295, 1296, 1296, 1297, 1298,
+     1299, 1300, 1301, 1302, 1302, 1303, 1303, 1304, 1304, 1304,
+     1305, 1305, 1305, 1306, 1306, 1306, 1306, 1307, 1308, 1309,
+     1310, 1311, 1312, 1313, 1314, 1315, 1317, 1318, 1319, 1320,
+     1320, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328,
+     1329, 1330, 1331, 1332, 1332, 1332, 1332, 1332, 1332, 1333,
+
+     1334, 1334, 1334, 1334, 1335, 1336, 1336, 1336, 1336, 1336,
+     1336, 1336, 1336, 1336, 1336, 1336, 1337, 1338, 1339, 1340,
+     1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350,
+     1352, 1353, 1354, 1354, 1354, 1355, 1355, 1356, 1357, 1360,
+     1362, 1364, 1367, 1369, 1370, 1371, 1371, 1371, 1371, 1371,
+     1371, 1372, 1372, 1373, 1374, 1375, 1375, 1375, 1376, 1377,
+     1378, 1378, 1378, 1378, 1378, 1379, 1380, 1381, 1381, 1381,
+     1382, 1383, 1384, 1385, 1386, 1386, 1386, 1387, 1387, 1388,
+     1388, 1388, 1388, 1389, 1390, 1390, 1391, 1392, 1392, 1393,
+     1393, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394,
+
+     1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394,
+     1394, 1394, 1395, 1396, 1396, 1396, 1396, 1397, 1398, 1399,
+     1400, 1400, 1402, 1403, 1403, 1404, 1405, 1405, 1406, 1407,
+     1407, 1408, 1409, 1410, 1411, 1412, 1413, 1413, 1413, 1414,
+     1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424,
+     1424, 1424, 1424, 1424, 1424, 1424, 1424, 1425, 1425, 1425,
+     1426, 1427, 1428, 1429, 1430, 1430, 1430, 1430, 1430, 1430,
+     1430, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438,
+     1439, 1439, 1440, 1440, 1440, 1440, 1440, 1440, 1441, 1441,
+     1442, 1443, 1443, 1443, 1443, 1443, 1443, 1444, 1444, 1445,
+
+     1445, 1446, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1448,
+     1449, 1450, 1451, 1452, 1453, 1453, 1454, 1454, 1454, 1454,
+     1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454,
+     1454, 1454, 1454, 1454, 1454, 1455, 1455, 1455, 1455, 1455,
+     1455, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1462,
+     1463, 1464, 1465, 1466, 1466, 1467, 1468, 1469, 1470, 1471,
+     1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471,
+     1471, 1471, 1472, 1473, 1474, 1474, 1474, 1474, 1475, 1475,
+     1476, 1477, 1478, 1479, 1480, 1481, 1482, 1482, 1482, 1482,
+     1483, 1484, 1485, 1485, 1485, 1485, 1485, 1486, 1487, 1487,
+
+     1487, 1488, 1488, 1489, 1489, 1489, 1490, 1491, 1492, 1493,
+     1494, 1494, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495,
+     1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495,
+     1495, 1495, 1495, 1495, 1495, 1495, 1496, 1497, 1498, 1498,
+     1498, 1499, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506,
+     1507, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508,
+     1508, 1508, 1508, 1508, 1508, 1508, 1508, 1509, 1510, 1510,
+     1511, 1511, 1511, 1512, 1513, 1513, 1513, 1513, 1513, 1513,
+     1513, 1514, 1514, 1514, 1514, 1514, 1515, 1515, 1515, 1516,
+     1517, 1517, 1518, 1518, 1518, 1519, 1520, 1521, 1521, 1521,
+
+     1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521,
+     1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521,
+     1522, 1524, 1525, 1525, 1525, 1525, 1526, 1526, 1526, 1526,
+     1526, 1526, 1526, 1526, 1526, 1527, 1527, 1528, 1529, 1529,
+     1529, 1529, 1529, 1529, 1529, 1530, 1530, 1530, 1530, 1530,
+     1530, 1531, 1532, 1533, 1534, 1535, 1536, 1536, 1536, 1536,
+     1536, 1536, 1537, 1538, 1539, 1540, 1541, 1541, 1541, 1541,
+     1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541, 1541,
+     1541, 1541, 1541, 1541, 1541, 1542, 1543, 1543, 1543, 1544,
+     1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1546,
+
+     1547, 1547, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1553,
+     1553, 1553, 1553, 1553, 1554, 1555, 1555, 1555, 1555, 1555,
+     1555, 1555, 1555, 1556, 1557, 1558, 1559, 1559, 1560, 1561,
+     1562, 1563, 1564, 1564, 1564, 1564, 1564, 1564, 1564, 1564,
+     1564, 1565, 1565, 1566, 1566, 1566, 1566, 1566, 1566, 1567,
+     1568, 1568, 1568, 1568, 1568, 1569, 1570, 1570, 1570, 1570,
+     1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1578,
+     1578, 1578, 1578, 1578, 1579, 1580, 1581, 1582, 1583, 1584,
+     1585, 1586, 1587, 1588, 1589, 1589, 1590, 1591, 1592, 1592,
+     1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592,
+
+     1592, 1592, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599,
+     1600, 1601, 1602, 1602, 1602, 1603, 1605, 1606, 1607, 1608,
+     1609, 1609, 1610, 1610, 1610, 1610, 1610, 1611, 1612, 1613,
+     1614, 1615, 1616, 1617, 1617, 1618, 1619, 1619, 1619, 1619,
+     1620, 1621, 1621, 1622, 1622, 1622, 1622, 1622, 1623, 1624,
+     1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625,
+     1625, 1625, 1625, 1625, 1625, 1625, 1626, 1626, 1626, 1626,
+     1626, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627,
+     1627, 1627, 1628, 1628, 1629, 1629, 1629, 1629, 1629, 1629,
+     1629, 1629, 1630, 1630, 1630, 1630, 1630, 1631, 1631, 1631,
+
+     1632, 1632, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633,
+     1633, 1634, 1634, 1634, 1635, 1635
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        4,    4,    5,    4,    4,    4,    4,    4,    4,    4,
+        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
+        4,    6,    7,    8,    9,   10,   11,   10,   12,   13,
+       14,   15,   15,   16,   17,   18,   15,   19,   19,   19,
+       20,   20,   20,   20,   20,   20,   20,   15,   21,   22,
+       23,   24,   25,   26,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       26,   26,   26,   26,   26,   26,   27,   28,   29,   30,
+
+       31,   32,   33,   34,   35,   25,   36,   37,   38,   39,
+       40,   41,   42,   43,   44,   45,   46,   47,   48,   49,
+       50,   51,   52,   26,   53,   26,   26,   54,   55,   56,
+       57,   58,   57,   59,   60,   61,   62,   63,   63,   63,
+       63,   63,   63,   63,   63,   64,   63,   64,   63,   63,
+       65,   66,   63,   63,   63,   63,   63,   63,   63,   67,
+       63,   63,   68,   69,   70,   63,   66,   66,   66,   66,
+       63,   71,   63,   63,   63,   63,   63,   63,   63,   63,
+       68,   63,   63,   63,   63,   67,   72,   63,   63,   63,
+       63,   73,   73,   74,   75,   76,   76,   76,   76,   76,
+
+       76,   76,   76,   76,   76,   77,   78,   78,   78,   78,
+       78,   78,   78,   78,   78,   78,   78,   78,   78,   78,
+       78,   78,   78,   79,   79,   80,   81,   81,   81,   81,
+       81,   81,   81,   81,   81,   81,   81,   81,   81,   82,
+       82,   82,   82,   82,   82,   82,   82,   83,   83,   83,
+       83,   83,   83,   83,   83
+    } ;
+
+static yyconst flex_int32_t yy_meta[85] =
+    {   0,
+        1,    2,    3,    1,    4,    5,    6,    7,    6,    1,
+        1,    8,    1,    1,    1,    1,    1,    1,    8,    8,
+        1,    1,    8,    9,    8,    1,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    1,   10,   11,   12,   11,   11,   11,   12,   11,
+       11,   11,   11,   13,   11,   11,   11,   11,   11,   11,
+       11,   11,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,   11,   11
+    } ;
+
+static yyconst flex_int16_t yy_base[3466] =
+    {   0,
+        0,    9,   93,    0,  177,    0,  259,  263,  269,    0,
+      353,    0,  437,    0,  521,    0,  605,    0,  689,    0,
+      773,    0,  857,    0,  941,    0, 1025,    0, 1109,    0,
+     1193,    0, 1277,    0, 1361,    0, 1443, 1447, 1451, 1455,
+     1461,    0, 1545,    0, 1629,    0, 1713,    0, 1795, 1799,
+     1803, 1807, 1811, 1815, 1868,    0, 1952,    0, 2036,    0,
+     2120,    0, 1819, 1823, 1828, 1832, 1844, 1848, 2204,    0,
+     2288,    0, 2372,    0, 2456,    0, 2540,    0, 1854, 2623,
+     2628, 2633, 2657,    0, 1860, 2637, 2642, 2648, 2739, 2743,
+     2775,    0, 2748, 2753, 2857, 2861, 2893,    0, 2977,    0,
+
+     3061,    0, 3145,    0, 2866, 3227, 3251,    0, 3335,    0,
+     3419,    0, 3503,    0, 3587,    0, 3671,    0, 3755,    0,
+     3839,    0,11461,26921,26921,26921,26921,26921,    0, 3922,
+     4004, 4085,    0, 1817, 2719,11408, 2729, 1799, 2836,11410,
+     3200, 1822, 2848,  232, 1420,11397, 3898,11374, 3899, 3916,
+     3932, 1802,11384, 2841,11380, 4165,    0,    0,26921,26921,
+    26921,26921,26921,26921, 3165,11377,26921,26921,26921,    0,
+        0,    0, 4249,11372,    0,26921,11371, 4321, 4340, 4359,
+    26921,26921, 3908, 3985, 4427,    0,    0, 4019, 4036, 4507,
+        0,    0, 4591,    0,    0,    0, 4046,    0, 4671, 2744,
+
+     2749, 4056, 4066, 4751,    0,    0, 4102, 4112, 4831,    0,
+        0, 4122, 4132, 4911,    0,    0, 4165, 4262, 4991,    0,
+        0, 4272, 4282, 5071,    0,    0, 4292, 4360, 5151,    0,
+        0, 4370, 4380, 5231,    0,    0, 4390, 4427, 5311,    0,
+        0, 4440, 4450, 5391,    0,    0, 4460, 4470, 5471,    0,
+        0, 4507, 4604, 5551,    0,    0,    0,    0,    0,    0,
+        0, 4623, 4633, 5631,    0,    0, 4684, 4694, 5711,    0,
+        0, 4704, 4714, 5791,    0,    0, 4751, 4764, 5871,    0,
+        0,26921,26921,26921,    0,    0,    0,    0,26921,26921,
+    26921,26921,26921,26921, 4774, 4784, 5951,    0,    0, 4794,
+
+     4831, 6031,    0,    0, 4844, 4854, 6111,    0,    0, 4864,
+     4874, 6191,    0,    0,26921, 3921, 3959, 4983,26921,    2,
+    26921,26921,26921, 4927, 4937, 4947,11374,26921, 4957,    0,
+     1796, 3926,    0, 3943,    0,    0, 6257,    0,    0, 4991,
+     5004, 6336,    0,    0, 5014, 5024, 6416,    0,    0, 5034,
+     5071, 6496,    0,    0, 5084, 5094, 6576,    0,    0,    0,
+        0,    0,    0,26921,    0,    0,26921, 5104, 5114, 6656,
+        0,    0,    0,    0,    0,11342, 5151, 5164, 6736,    0,
+        0,    0,    0,    0,11341, 5174, 5184, 6816,    0,    0,
+     5194, 5231, 6896,    0,    0, 5244, 5254, 6976,    0,    0,
+
+    26921,26921,26921,26921,    0,    0,    0,11374, 5264, 5274,
+     7056,    0,    0, 5311, 5324, 7136,    0,    0, 5334, 5344,
+     7216,    0,    0,26921,26921,    0,    0,    0, 5354, 5391,
+     7296,    0,    0, 5404, 5414, 7376,    0,    0, 5424, 5434,
+     7456,    0,    0, 5471, 5484, 7536,    0,    0,    0, 7619,
+     7700, 2868,26921, 7780,    0,    0, 7863,    0, 4030,11329,
+     3915, 2601, 5538,11351, 5540, 2616, 5541, 1424, 1776,11338,
+     5551,11309, 5542, 5597, 5613, 3195,11318, 4062,11308,    0,
+     4067,11308, 3890,11287,11284, 2768,11292, 2606,11287, 2723,
+    11265, 5594, 2832,11269,11264,11231, 5557,11246, 2839,11239,
+
+    11246,11225,11198, 3887,11208, 3923,11204, 3922,11202,11151,
+     4685, 3903, 4686,11154,11147, 5623, 1801, 5583,11149, 2847,
+     5677,11137,11139,11128, 3932, 4109, 4055, 5662,11142, 4148,
+    11119,11115, 5665, 3910, 4123,11112,11069, 4434,11083, 5674,
+    11061, 4121, 7914,11058, 3949,11033,11037, 4687, 4955,    0,
+        0,26921,    0,    0,    0,26921,26921,    0,    0, 7998,
+     5649,11060,26921,11059, 8070, 8089, 8108,    0, 8127, 5652,
+     8195,    0,    0,    0,    0, 5662, 8275,    0,    0,    0,
+        0, 8359,    0, 5682, 8439, 4149, 4960, 5724, 8519,    0,
+        0,    0,    0, 4961,    0, 5711, 8599,    0,    0,    0,
+
+        0, 5734, 8679,    0,    0,    0,    0, 5744, 8759,    0,
+        0,    0,    0, 5754, 8839,    0,    0,    0,    0, 5791,
+     8919,    0,    0,    0,    0, 5804, 8999,    0,    0,    0,
+        0, 5814, 9079,    0,    0,    0,    0, 5824, 9159,    0,
+        0,    0,    0, 5834, 9239,    0,    0,    0,    0, 5871,
+     9319,    0,    0,    0,    0, 5884, 9399,    0,    0,    0,
+        0,    0,    0, 5894, 9479,    0,    0,    0,    0, 5904,
+     9559,    0,    0,    0,    0, 5914, 9639,    0,    0,    0,
+        0, 5951, 9719,    0,    0,    0,    0,    0, 5964, 9799,
+        0,    0,    0,    0, 5974, 9879,    0,    0,    0,    0,
+
+     5984, 9959,    0,    0,    0,    0, 5994,10039,    0,    0,
+        0,    0, 5640, 5659,26921,26921, 4472, 6069, 6124, 6149,
+     6204,26921,    0,    0,    0, 6031,    0, 5515, 5514,    0,
+     5598,    0,    0,10105,    0,    0,11047, 6111, 6160, 6214,
+     6294,    0,    0, 5521, 4985,    0,    0, 6295, 6240,    0,
+        0,    0, 6044,10184,    0,    0,    0,    0, 6304,10264,
+        0,    0,    0,    0, 6336,10344,    0,    0,    0,    0,
+     6349,10424,    0,    0,    0,    0,    0,    0, 6359,10504,
+        0,    0,    0,    0,    0,10993, 6369,10584,    0,    0,
+        0,    0,    0,10992, 6379,10664,    0,    0,    0,    0,
+
+     6416,10744,    0,    0,    0,    0, 6429,10824,    0,    0,
+        0,    0,26921,    0,    0,11028, 6439,10904,    0,    0,
+        0,    0, 6449,10984,    0,    0,    0,    0, 6459,11064,
+        0,    0,    0,    0,26921,    0,    0, 6496,11144,    0,
+        0,    0,    0, 6509,11224,    0,    0,    0,    0, 6519,
+    11304,    0,    0,    0,    0, 6529,11384,    0,    0,    0,
+        0,11467,11548, 4440, 4178, 5672, 4685, 6647, 6262, 6648,
+    10994, 5633, 4514, 4515, 4177, 5601, 4758, 6263, 6131, 6264,
+     6649, 6650,10982, 4131, 4438,10970, 4517, 4759, 4679, 4651,
+    10955, 6618, 6307, 4760, 5643, 4681, 5714, 6656, 5715, 4838,
+
+     6099, 6100, 5544, 6666,11630, 6664, 6348, 6727, 6728, 6729,
+     6730, 6698, 6740, 6741, 4839, 6742, 6807, 6887, 6743, 4520,
+     6749,10954,10946, 6808, 6671, 6783, 4947, 5623, 4948, 6900,
+     6967, 6810, 6821, 6823, 6829, 6901, 6122, 6772, 4952, 6171,
+     6826, 4762, 6177, 6824, 6980, 6903, 6855, 6101, 6968, 6889,
+     6182, 6932, 6982, 6673, 6983, 5078, 5079,10917,10916,10915,
+    10914,10902,10890, 4065, 6985, 6902, 5680, 7011,10875, 4840,
+     7047, 7012,10874,11714, 7003,26921, 6123,26921, 7052,11796,
+        0,    0, 6170, 5158, 5159, 6321, 7060, 7061, 7062, 7090,
+     7067, 7128, 7068,    0,    0,    0,    0,26921,11868,    0,
+
+        0, 6131,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,26921, 7079, 7096, 7160, 7176, 7240, 7256,10902,
+     7320, 7336, 7400, 7416,    0, 7480, 7496, 7576,    0,    0,
+    26921,26921, 7136, 7216, 7586, 7634, 7666, 7676,10873, 7717,
+     7731, 7800, 8215,    0, 8228, 8245, 8472, 7149,10795,    0,
+        0,    0,    0,    0,    0, 5197,    0, 5275,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    11939,12020, 6108,12102, 6679, 7103, 6273,12186, 7302, 6356,
+     4929,10843, 6310, 5011, 6579, 6586, 7343, 6267, 7419, 7499,
+
+     7141, 7340,12270, 7382,12354,12438, 6676, 5086, 5250, 6582,
+     5330, 5331, 6751, 6909, 5404, 6916,12520, 6584, 6585, 7579,
+     7143, 7420, 5247, 5089, 7607, 5804, 7341, 7608, 7448, 7500,
+     8199,10828,12604, 6993,26921,26921,10780,    0,    0, 7641,
+     7384, 5405, 5169,10803, 7501, 7642, 7529, 7726,12688, 7463,
+    12772, 5328,10802, 7684, 6632, 7822, 7304, 5566, 6326, 5644,
+     5811, 5890, 5891, 6727, 6588, 5964,10787, 6652,10756, 5492,
+    10768,10767, 6730,10728,10714, 7823, 8082, 7729, 7541, 7852,
+     5329,10722, 7670, 6429, 8083, 6187, 5714, 5408, 6665, 5409,
+     6800, 5489,10700,10678,10684,10671,10682,10660,10658, 8200,
+
+     8443, 7671, 7731, 7000, 8267, 8084, 7543, 7824, 8202, 7542,
+     8444, 8085, 7075, 8201, 8281, 8207, 7078, 5690, 7540, 6738,
+     8214, 8446, 7682, 8280, 6051,10642, 6509, 5718, 6660,10635,
+    10634,10590, 8445, 8458, 7763, 8526, 5808, 8459, 8090, 8524,
+     5996, 5246, 8562, 8591, 8525, 8532, 8527, 8534,10602, 7049,
+    10589, 6430, 8533, 5886, 8592, 8096, 8594, 8599, 8451, 8606,
+    10627, 8097, 8609, 8617, 8611, 8670, 8614, 6516, 8616, 6743,
+    12856, 8215, 7105, 6791,10576,10566, 8644, 5889,10563, 8672,
+        0, 8643, 8679, 8692, 8703, 8723, 8783, 8803, 8863, 8883,
+     8943, 8963, 9023, 9043, 9103, 9123, 9183,10590, 9203, 9263,
+
+     9283,10582, 9343, 9363, 9423, 9443, 9503, 9523,10553, 9583,
+     9603, 9663, 9683,10552, 9743, 9763, 9823,    0, 8275, 8759,
+     9903, 9913, 9993,10003,10059,10139,10149,10204,10234,10285,
+    10297,10365,10377,10445,10551,10457,10525,10537,10550,10605,
+    10617,10685,10697,10765,10777,10526,10845,10857,10925,10937,
+    10511,11005,11017,11085,10454, 5997, 6077,12939,13020, 6154,
+    13102,26921,26921,13184,    0,    0, 8213, 7301, 7140, 6302,
+    13268, 8686,26921, 6771,26921, 7609,    0,    0,    0, 8786,
+     6837, 6890, 6991, 8453, 7624,10458, 7069, 7131, 7385, 8270,
+     7882, 7261, 7683, 8691, 7383, 7581, 8684, 8696,10445, 7632,
+
+     7181,13352,26921,26921,    0,    0,    0, 8844, 7259, 7260,
+    13436, 8846,26921,26921,    0,    0,    0, 7376,13520, 8910,
+    26921, 7449,26921,    0,    0,    0, 7460, 8847, 7724, 7676,
+     7814, 8452, 8849, 7817,13604, 9870, 8886, 8919, 8911, 8966,
+    10444, 7816, 7815, 8990, 8208, 8912, 7825, 8925, 9004, 9005,
+     8091, 8993, 4861, 8104, 8106, 8947, 8268, 8999,10443, 8646,
+     8628, 9070, 9079,10442, 9126, 9071, 9084, 9085, 9150, 9163,
+     9164, 8220, 8222,13688, 8992,26921,26921,    0,    0,    0,
+     9165,10416, 8535, 9166, 9187,10404, 9086, 9206, 9243, 8269,
+     9231, 9244, 9072, 9319, 9073,10407,10401,10380,10347,10356,
+
+    10348,10346,10314,10305, 6312,10276,10248,10231, 8465, 9153,
+     9245, 8467, 9886, 9324,10242, 8726, 9366,10240, 9234, 9233,
+     9310, 8787, 9268, 9246, 9347, 9087, 9395, 9403,10221,10209,
+    10186,10194, 9474,10206,10149, 8788, 9404,10127, 9325, 9348,
+    10110, 9479, 8913, 8946, 9312, 9484, 9485, 9152, 9393,10147,
+     9406,10138, 9559,13772, 9507, 9564,10097, 9550, 9313, 9409,
+     9428, 9487,10049,10044,10018, 9606, 9639, 9472, 9551, 9473,
+     9630, 9644, 9666,10027,10003, 9553, 9569, 9966,11148, 9567,
+     9632, 9486, 9566, 9982, 9633, 9719, 9712, 9686, 9977, 9646,
+     9993, 9713, 5981, 9647, 9668, 9725, 9790, 9728, 9791, 9766,
+
+     9748, 9804, 9809, 9792,13856, 9871,26921,26921, 9885,    0,
+        0,    0, 9908, 9951, 9806, 9807, 9926, 9920, 9793, 9844,
+     9907, 9872, 9959,10309,10389,10469,10549,10629,10709,10789,
+    10869,10949,11029,11165,11178,11188,11268,11317,11327,11348,
+    11407,11454,11488,11499,11515,11809,11819,11829,11839,11955,
+    11981,11991,10217,11144,12954,12971,12984,13001,13938,13948,
+    13978,13989,14029,14040,14070,14080,14121,14131,14161,14172,
+    14212,14223,14253,14263,14304,14314,14344,14355,14395,14406,
+    14436,14446,    0,14527,14608,11798,10113,11940,14690,10123,
+     9846, 9873, 9879,11473, 9890,11468,10188,11941,11149,11800,
+
+    11958,11151,11963,12044,10125,12046,12522,11295,12524,12940,
+     9897,12942,12945,11298,12952,12959,13186, 9867,13188, 9884,
+     9909,10124, 9874,11296,13940,12962,11304,13941,13950,13947,
+    13959,13952,14774,26921,26921,14042,14528,14856,    0,    0,
+    12001, 9814, 9808,14133,14225,11470,14135,14186,14316, 9789,
+    14318,14408,11498,14369, 9915,14460,11309,14501,14534,11310,
+    14539,14546, 9801, 9784,14551,11410, 9918,14609,11412,14588,
+    14611, 9756,14614,14621,11411,14631, 9920, 9921,14858, 9755,
+    14860,14927,11493,14973,11580, 9923,15056,11596,15101,11805,
+    11807, 9952, 9953,11499,15059,26921,15068,15071,11817,15081,
+
+    15184, 9742,15090,15185,15186,15195,15197,15198,15232, 9710,
+     9718,11942,11949, 9721,11948, 9692, 9699, 9685, 9688, 9689,
+     9684,11950, 9682, 9959,15207,11812,15244,15246, 9645,15258,
+     9967,15269, 9968,15249,12004,15259,15271,15292,10043, 9644,
+     9658, 9636, 9998,10055, 9638, 9606,15304, 9595,15306,15318,
+     9606,15317,10005,15329,15351, 9579, 9564,15352,12533,15363,
+     9588,12530,15372,15377,15423,26921,26921,15506,    0,    0,
+        0,12954,10086,15508, 9547,15509,15511,13000,15518,15521,
+    15528, 9521,26921, 9519,15559,15566,15569,15571,15576, 9526,
+     9489,15578,15588,15589,15619,15626,15631,15636,15637,15648,
+
+     9470, 9449, 9464, 9437, 6932, 9441, 6041,10045,15678,12535,
+    15689, 9420,15679,15690,15696, 9403,10046,15731,12544,15738,
+    15701, 9416,15743,12541,13065,13067,15772,14072,15757,15818,
+    12536,10048,10053,15769,10058, 9396,15901,26921,15903,15904,
+    15906,15923,15918, 9387, 9383, 9372,15949,15956,12543,15961,
+     9372,15968, 9355,15974, 9359,16020,16103, 9357,16104,16105,
+     9336,16114,16116, 9317,16123,16125, 9302,16126,16171, 9303,
+    16173,16174,16176,26921,16185, 9323,16188,16219,13196,16226,
+    16233,16236, 9299, 9277,16238,16239, 9286,16284,16245,26921,
+    16286, 9261,16291,13197,10085,16293,16296,16306, 9258, 9260,
+
+    16305,12953,16339,16348,16351,26921,16353,16360,26921,16362,
+        0,13194,26921,26921,    0,    0,    0,10112,10114,    0,
+        0,13203,    0,    0,    0,    0,16365,10115,16374,13205,
+    16399, 9246,16408,16411,16428,16417,16429,16438, 9211, 9214,
+    13206,14166,13960,26921,14073, 9197, 9194, 9164, 9180,26921,
+     9159,14255,14088, 9150,10143,14256,14656,16458,26921,16459,
+    13953,16471,10148,10154,16477,10189,16489,14347,16496,16506,
+    10335,10194, 9149,10415,14438,10256, 9142,10495,16518,26921,
+    16527,16539, 9132,16548,16545, 9128, 9126,16557,14349,16560,
+    10195,16582, 9124,14164, 9123,16591,10257,14536,16602,10197,
+
+    10258,16603,26921,16605,16608, 9076,16617,16620, 9049, 9034,
+    16650,16651,16663,16662,11110,11111,16669,16672,16681,16710,
+    16715,16720,16727,16730,16740,16741, 9006, 9011, 9016, 8984,
+     8990, 8990, 8972, 8982, 8967,10202,16775, 8964,16778,16787,
+    16789,26921,16796,16790,16835, 8948,16837,16838, 6116,10203,
+    16844,14559,14573,16858,14271, 8927,16847,16864,16889,16937,
+     8899, 8899,10575,17020,17021, 8885,17022, 8899,17023, 8887,
+    17032,    0,14869,26921,10655,26921,    0,    0,    0,17041,
+     8857,17070, 8844,17071,17080, 8830,17082,26921,17092,17091,
+     8829,17093,17105,17139,17142, 8835,17144,16476,17151,14619,
+
+    17153, 8841, 8811,17156, 8802,17162,17173, 8800,17203, 8780,
+    17204,17214, 8760, 8758,17215,17234,17221,14866,17260,10204,
+    17263, 8739,17272,17273,17283,17282,17320, 8694, 8681,14439,
+    10259,14871, 8669, 8673,26921, 8684,10337,14876,14877,14930,
+    17285,14936,10269,17330,10338,17332,17337,17339,17349,17380,
+    17386, 8664,10735,10815,14928,10300, 8666,10895,17391, 8655,
+    17398,17401, 8650, 8651,17411,14874,10340,17432,17444,10349,
+    14879,17446,10350,11135,17449, 8634,17458,17461,26921, 8598,
+    17467,17487,17506,14939,17509,17512,14941,17521,10417,11138,
+    10418,11060,17524,17543,17554,17566,17580,17585,17591,17592,
+
+    17597,17611, 8596, 8595, 8571, 8578, 8590, 8562, 8525, 8531,
+     8531,17614,26921,17634,17644,17645,17657,17656,26921,10420,
+    17659,14942,15057, 8528,17671,17682, 8505,10429,10975,17702,
+    26921,17704, 8514,17705, 8504,10430,11055,15062,17716, 8444,
+    17717,26921,17719,26921,17739,17750,26921,17762,17764,17765,
+    17787, 8441,17799,17810, 8424, 8417,17816, 8276, 8257,17817,
+    26921,17822,17828,10497,17851, 8248,17837,17863, 8186, 8176,
+    17876,17886,17885,26921,17888,17898,17911,17923, 8162, 8091,
+    11229,15337,15069, 8094, 8065, 8057,11458,15364,15110,17936,
+    11322,17937,17946,17948,17958,17949,17991, 8051,11228, 8078,
+
+    17997,26921,18000,18006, 8055, 7876,18003,18017,18018,11311,
+    18020,10498,18051,26921,18063,18065,18068,18070,10510,11320,
+    18088,18085,18111,18122,18123,18133,18144,18153,18171, 7852,
+     7851, 7844, 7844, 7847,26921, 7841, 7843, 7827,18156,15116,
+    18174,18183,10500,18194,18204,15196,11597,10509,18209,18216,
+     7826,18221, 7806,10577,18231, 7805,18243,18254,18264,18266,
+    15119,18269, 7770,18291,18303, 7786, 7775, 6892, 7762,18314,
+    15076,18316,15131,10578,18321, 7766,18326,18333, 7757,10580,
+    18336,18359,18371,26921,26921,15371,10625, 7740, 7737,15596,
+    18374,10589,18384,18386,18396,18393,    0,11989, 7722,18405,
+
+    18431, 7735,15397,18419,18438,18444,11150,18450,15206,10590,
+    18456,18457,18469,18479,11553,10657,18491,18504,18498,18510,
+    18521,18516,18533,18547,18558, 7734, 7725, 7703, 7719, 7681,
+     7685, 7683, 7674,18564, 7646,18559,18584,15398,18585, 7605,
+    12947,18597,18607,26921,18610,26921,18619,26921,18630,18632,
+    18644,18649, 7608,18661, 7593,18667,18678, 7600, 7586, 7592,
+     7572,18679, 7585,18692, 7553,18690,18709,15519, 7537,10658,
+    18712,15691,18729,15586, 7511, 7523, 7496, 7496, 7513, 7478,
+    16115,18727,18738,18750,18739,13942, 7478,18760,18785,15639,
+     7478,15646,18795,18797,18812,11457,18798,18815,10670,18832,
+
+    18845,18850,18862,18875,18880,18897,18909, 7463, 7445, 7439,
+     7424, 7427, 7412, 7423, 7403,18914, 7402,18926,15699,18943,
+    15649,15746,18936, 7386,18948,18955,18957, 7377,18969, 7357,
+    18986,19000, 7344, 7347,26921, 7322,19003, 7324,19006, 7301,
+    19012,10737,19023, 7281,15913, 7263, 7274, 7261, 7225, 7216,
+     7216,15986,19021,19033,19054,19060, 7197,19066,10738,19071,
+    19080,19083,10750,19081,15791,19093,19114,19126,19128,19131,
+    19145,19151,19157,19174, 7214, 7205, 7182, 7149, 7149, 7146,
+     7119, 7123,19186, 7115,19192, 7101,19203, 7100,19205,15520,
+    19212, 7062,19223, 7044,19225,19238, 7044, 7044,19250,26921,
+
+    19260, 7041,19272,15698,10740,19275, 7020,15921, 7026, 7013,
+     7024, 6997, 6956,26921,16113,19273,16732,19295,16895,19310,
+    16897, 6955,19293,15777,15788,19298,19320,19332,10749,10817,
+    19341,15912,19343,19358,19363,19378,19388,19397, 6959, 6956,
+    26921, 6942,26921, 6948, 6907, 6885,19400, 6902,19409, 6852,
+    19419, 6847,19431,10829,19477,15966,19560,19561, 6829, 6834,
+    19563,10818,19566,15915,10820,19572,26921,15969, 6823, 6801,
+     6799, 6771, 6743,15979,19609, 6252,19611, 6445,19614, 6447,
+    14039,19621,15995,16106,19620,19634,26921,10830,19640,19659,
+    19669,19671,19681,19682, 6725, 6715, 6691, 6670, 6638, 6620,
+
+    19688, 6634,19700,26921,19719,10897,19729,16182,19730,10898,
+    26921,19731,    0,16419,26921,26921,16183,    0,    0,    0,
+    16256,10900,19741,19742, 6570, 6568,19748,16193,10909,10910,
+    26921,10977,10978, 6512,14079,19768,19787,19790,19793,26921,
+    26921, 6515,26921, 6501, 6513,19802, 6353,19805,16244,10980,
+    16294,16304,10989,19820,19839, 6320, 6233,11814,13036,13066,
+     6205,19840,19850,19851, 6172,26921, 6115,19881, 6054,19861,
+    10990, 5794, 5717,19888,19898,19903, 5678, 5654,19908, 5620,
+    19915,11057, 5589, 5553,19918,19933,19945, 5494, 5006,19956,
+     4947,11058, 4915,19966,19968, 4120,26921,19978, 4037,11069,
+
+     3978,26921,19987, 3948, 3928,20001, 3214, 3204,20013, 2832,
+    26921,20016, 2699,26921,26921,20062,20075,20088,20101,20114,
+    20127,20140,20153,20166,20179,20192,20205,20218,20231,20244,
+    20254,20267,20280,20290,20303,20316,20329,20342,20352,20365,
+    20378,20388,20401,20414,20427,20437,20450,20463,20473,20486,
+    20499,20509,20522,20535,20545,20558,20571,20581,20594,20607,
+    20617,20630,20643,20653,20666,20679,20689,20702,20715,20725,
+    20738,20751,20761,20774,20787,20797,20810,20823,20833,20846,
+    20859,20872,20885,20895,20908,20921,20931,20944,20957,20967,
+    20980,20993,21003,21016,21029,21042,21052,21065,21078,21088,
+
+    21101,21114,21124,21137,21150,21160,21173,21186,21199,21212,
+     2648,21222,21235,21248,21261,21274,21287,21300,21310,21323,
+    21336,21346,21359,21372,21382,21395,21408,21418,21431,21444,
+    21457,21470,21480,21493,21506,21519,21529,21542,21555,21568,
+    21578,21591,21604,21614,21627,21640,21650,21663,21676,21689,
+    21702,21715,21725,21738,21751,21761,21774,21787,21797,21810,
+    21823,21836,21849,21862,21872,21885,21898,21908,21921,21934,
+    21944,21957,21970,21980,21993,22006,22019,22029,22042,22055,
+    22068,22081,22094,22107,22120,22133,22146,22156,22169,22182,
+    22195,22205,22218,22231,22244,22257,22267,22280,22293,22306,
+
+    22319,22332,22345,22355,22368,22381,22394,22404,22417,22430,
+    22443,22453,22466,22479,22492,22502,22515,22528,22541,22551,
+    22564,22577,22590,22600,22613,22626,22639,22649,22662,22675,
+    22688,22698,22711,22724,22737,22747,22760,22773,22786,22796,
+    22809,22822,22835,22845,22858,22871,22884,22897,22910,22920,
+    22933,22946,22959,22969,22982,22995,23008,23018,23031,23044,
+    23057,23067,23080,23093,23106,23119,23129,23142,23155,23168,
+    23178,23191,23204,23217,23227,23240,23253,23266,23276,23289,
+    23302,23315,23328,23341,23354,23367,23380,23393,23406, 2619,
+    23419,23432,23445,23458,23471,23484,23497,23510,23523,23536,
+
+    23549,23562,23575,23585,23598,23611,23624,23634,23647,23660,
+    23673,23683,23696,23709,23722,23732,23745,23758,23771,23784,
+    23797,23807,23820,23833,23846,23859,23869,23882,23895,23908,
+    23921,23931,23944,23957,23970,23980,23993,24006,24019,24029,
+    24042,24055,24068,24081,24094,24104,24117,24130,24143,24153,
+    24166,24179,24192,24202,24215,24228,24241,24254,24267,24277,
+    24290,24303,24316,24326,24339,24352,24365,24375,24388,24401,
+    24414,24424,24437,24450,24463,24473,24486,24499,24512,24525,
+    24538,24551,24564,24577,24590,24603,24616,24629,24642,24655,
+    24668,24681,24694,24707,24720,24733,24746,24759,24772,24785,
+
+    24798,24811,24824,24837,24850,24863,24876,24889,24902,24915,
+    24928,24941,24954,24967,24980,24993,25006,25019,25032,25045,
+    25058,25071,25084,25097,25110,25123,25136,25149,25162,25175,
+    25188, 1819,25201,25214,25227,25240,25253,25266,25279,25292,
+    25305,25318,25331,25344,25357,25370,25383,25396,25409,25422,
+    25435,25448,25458,25471,25484,25497,25510,25523,25536,25549,
+    25562,25575,25588,25601,25614,25627,25640,25653,25666,25679,
+    25692,25705,25718,25731,25744,25757,25770,25783,25796,25809,
+    25822,25835,25848,25861,25874,25887,25900,25913,25926,25939,
+    25952,25965,25978,25991,26004,26017,26030,26043,26053,26066,
+
+    26079,26092,26105,26118,26131,26144,26157,26170,26183,26196,
+    26209,26222,26235,26248,26261,26274,26287,26300,26313,26326,
+    26339,26352,26365,26378,26391,26404,26417,26430,26443,26456,
+    26469,26482,26495,26508,26521,26534,26547,26560,26573,26586,
+    26599,26612,26625,26638,26651,26663,26673,26686,26699,26712,
+    26725,26738,26751,26764,26777,26790,26803,26816,26829,26842,
+    26855,26868,26881,26894,26907
+    } ;
+
+static yyconst flex_int16_t yy_def[3466] =
+    {   0,
+     2916, 2915, 2915,    3, 2915,    5, 2917, 2917, 2915,    9,
+     2915,   11, 2915,   13, 2915,   15, 2915,   17, 2915,   19,
+     2915,   21, 2915,   23, 2915,   25, 2915,   27, 2915,   29,
+     2915,   31, 2915,   33, 2915,   35, 2918, 2918, 2919, 2919,
+     2915,   41, 2915,   43, 2915,   45, 2915,   47, 2920, 2920,
+     2921, 2921, 2922, 2922, 2915,   55, 2915,   57, 2915,   59,
+     2915,   61, 2923, 2923, 2924, 2924, 2923, 2923, 2915,   69,
+     2915,   71, 2915,   73, 2915,   75, 2915,   77, 2925, 2925,
+     2926, 2926, 2915,   83, 2923, 2923, 2927, 2927, 2923, 2923,
+     2915,   91, 2928, 2928, 2923, 2923, 2915,   97, 2915,   99,
+
+     2915,  101, 2915,  103, 2923, 2923, 2915,  107, 2915,  109,
+     2915,  111, 2915,  113, 2915,  115, 2915,  117, 2915,  119,
+     2915,  121, 2915, 2915, 2915, 2915, 2915, 2915, 2929, 2930,
+     2915, 2930,  132,  131,  132,  132,  132,  132,  132,  132,
+      132,  132,  132,  132,  132,  132,  132,  132,  132,  132,
+      132,  132,  132,  132,  132, 2930, 2931, 2932, 2915, 2915,
+     2915, 2915, 2915, 2915, 2933, 2915, 2915, 2915, 2915, 2934,
+     2935, 2936, 2915, 2937,  173, 2915, 2937, 2937,  178,  178,
+     2915, 2915, 2938, 2938, 2938, 2939, 2940, 2941, 2941, 2941,
+     2942, 2943, 2915, 2944, 2944,  193, 2945, 2944,  193, 2946,
+
+     2947, 2948, 2948, 2948, 2949, 2950, 2951, 2951, 2951, 2952,
+     2953, 2954, 2954, 2954, 2955, 2956, 2957, 2957, 2957, 2958,
+     2959, 2960, 2960, 2960, 2961, 2962, 2963, 2963, 2963, 2964,
+     2965, 2966, 2966, 2966, 2967, 2968, 2969, 2969, 2969, 2970,
+     2971, 2972, 2972, 2972, 2973, 2974, 2975, 2975, 2975, 2976,
+     2977, 2978, 2978, 2978, 2979, 2980, 2981, 2981, 2981, 2982,
+     2982, 2983, 2983, 2983, 2984, 2985, 2986, 2986, 2986, 2987,
+     2988, 2989, 2989, 2989, 2990, 2991, 2992, 2992, 2992, 2993,
+     2994, 2915, 2915, 2915, 2995, 2995, 2995, 2995, 2915, 2915,
+     2915, 2915, 2915, 2915, 2996, 2996, 2996, 2997, 2998, 2999,
+
+     2999, 2999, 3000, 3001, 3002, 3002, 3002, 3003, 3004, 3005,
+     3005, 3005, 3006, 3007, 2915, 3008, 3008, 3008, 2915, 2915,
+     2915, 2915, 2915, 3009, 3010, 3011, 2915, 2915, 3012, 3013,
+     3013, 3013, 3013, 3013, 3013, 3014, 3015, 3016, 3017, 3018,
+     3018, 3018, 3019, 3020, 3021, 3021, 3021, 3022, 3023, 3024,
+     3024, 3024, 3025, 3026, 3027, 3027, 3027, 3028, 3029, 3030,
+     3030, 3030, 3031, 2915, 3031, 3031, 2915, 3032, 3032, 3032,
+     3033, 3034, 3035, 3035, 3035, 2915, 3036, 3036, 3036, 3037,
+     3038, 3039, 3039, 3039, 2915, 3040, 3040, 3040, 3041, 3042,
+     3043, 3043, 3043, 3044, 3045, 3046, 3046, 3046, 3047, 3048,
+
+     2915, 2915, 2915, 2915, 3049, 3050, 3051, 2915, 3052, 3052,
+     3052, 3053, 3054, 3055, 3055, 3055, 3056, 3057, 3058, 3058,
+     3058, 3059, 3060, 2915, 2915, 3061, 3062, 3063, 3064, 3064,
+     3064, 3065, 3066, 3067, 3067, 3067, 3068, 3069, 3070, 3070,
+     3070, 3071, 3072, 3073, 3073, 3073, 3074, 3075, 3076, 3077,
+     3077, 2915, 2915, 3077, 3078, 3079,  451,  457,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  457,
+      457,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451, 2915,  451,  451,  451,  451,  451,  451,  454,
+     3080, 2915, 3081, 3082, 3083, 2915, 2915, 3084, 3085, 2915,
+     2915, 3086, 2915, 3086, 3086,  565,  565,  565,  565, 3087,
+     3087, 3088, 3089,  571, 3090, 3091, 3091, 3092, 3093,  577,
+     3094, 2915, 3095, 3096,  582, 3097, 3098, 3096, 3096, 3099,
+     3100,  585,  589, 3101, 3102, 3103, 3103, 3104, 3105,  597,
+
+     3106, 3107, 3107, 3108, 3109,  603, 3110, 3111, 3111, 3112,
+     3113,  609, 3114, 3115, 3115, 3116, 3117,  615, 3118, 3119,
+     3119, 3120, 3121,  621, 3122, 3123, 3123, 3124, 3125,  627,
+     3126, 3127, 3127, 3128, 3129,  633, 3130, 3131, 3131, 3132,
+     3133,  639, 3134, 3135, 3135, 3136, 3137,  645, 3138, 3139,
+     3139, 3140, 3141,  651, 3142, 3143, 3143, 3144, 3145,  657,
+     3146, 3147, 3148, 3149, 3149, 3150, 3151,  665, 3152, 3153,
+     3153, 3154, 3155,  671, 3156, 3157, 3157, 3158, 3159,  677,
+     3160, 3161, 3161, 3162, 3163,  683, 3164, 3165, 3166, 3166,
+     3167, 3168,  690, 3169, 3170, 3170, 3171, 3172,  696, 3173,
+
+     3174, 3174, 3175, 3176,  702, 3177, 3178, 3178, 3179, 3180,
+      708, 3181, 3182, 2915, 2915, 2915, 2915, 3183, 3184, 3185,
+     3186, 2915, 3187, 3188, 3189, 3190, 3191, 3191, 3191, 3191,
+     3191, 3191, 3192, 3193, 3194, 3195, 2915, 3196, 3197, 3198,
+     3199, 3191, 3191, 3200, 3191, 3201, 3191, 3191, 3191, 3191,
+     3191, 3202, 3203, 3203, 3204, 3205,  754, 3206, 3207, 3207,
+     3208, 3209,  760, 3210, 3211, 3211, 3212, 3213,  766, 3214,
+     3215, 3215, 3216, 3217,  772, 3218, 3219, 3220, 3221, 3221,
+     3222, 3223,  780, 3224, 3225, 2915, 3226, 3226, 3227, 3228,
+      788, 3229, 3230, 2915, 3231, 3231, 3232, 3233,  796, 3234,
+
+     3235, 3235, 3236, 3237,  802, 3238, 3239, 3239, 3240, 3241,
+      808, 3242, 2915, 3243, 3244, 2915, 3245, 3245, 3246, 3247,
+      818, 3248, 3249, 3249, 3250, 3251,  824, 3252, 3253, 3253,
+     3254, 3255,  830, 3256, 2915, 3257, 3258, 3259, 3259, 3260,
+     3261,  839, 3262, 3263, 3263, 3264, 3265,  845, 3266, 3267,
+     3267, 3268, 3269,  851, 3270, 3271, 3271, 3272, 3273,  857,
+     3274, 3275, 3275,  863,  863,  863,  863,  863,  863, 2915,
+      863,  863,  863,  863,  863,  863,  863,  863, 2915,  863,
+      863,  863,  863,  863,  863,  863,  863,  863,  863,  863,
+      863,  863,  863,  863,  863,  863,  863,  863,  863,  863,
+
+      863,  863,  863,  863, 2915,  863,  863, 2915,  863,  863,
+      863,  863, 2915,  863,  863,  863,  863, 2915,  863,  863,
+      863,  863,  863,  863, 2915,  863,  863,  863,  863,  863,
+     2915,  863,  863,  863,  863,  863,  863,  863,  863,  863,
+      863,  863,  863,  863, 2915,  863,  863,  863,  863, 2915,
+      863,  863,  863, 2915,  863,  863,  863,  863,  863,  863,
+      863,  863,  863,  863,  863, 2915,  863,  863,  863,  863,
+      863,  863,  863, 2915, 3276, 2915,  863, 2915,  863, 3275,
+     3277, 3278,  863,  863,  863,  863,  863,  863, 2915,  863,
+      863, 2915,  863,  980, 3279, 3280, 3281, 2915, 3282, 3283,
+
+     3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293,
+     3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303,
+     3304, 3305, 2915, 3306, 3306, 3307, 3308, 3309, 3307, 3306,
+     3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319,
+     2915, 2915, 3320, 3320, 3321, 3322, 3323, 3321, 3320, 3324,
+     3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 2915, 3333,
+     3334, 3335, 3336, 3337, 3338, 2915, 3339, 2915, 3340, 3341,
+     3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351,
+     3352, 3352, 1082, 2915, 3353, 1082, 1082, 2915, 3354, 1082,
+     1082, 2915, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082,
+
+     2915, 1082, 2915, 3355, 2915, 2915, 1082, 1082, 1082, 1082,
+     1082, 1082, 1082, 2915, 1082, 1082, 3352, 1082, 1082, 1082,
+     2915, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 2915, 1082,
+     1082, 1082, 2915, 3356, 2915, 2915, 1117, 3357, 3358, 1082,
+     2915, 1082, 1082, 2915, 1082, 1082, 2915, 1082, 2915, 3359,
+     2915, 1082, 2915, 1082, 1082, 1082, 2915, 1082, 1082, 1082,
+     1082, 1082, 1082, 1082, 1082, 1082, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1082, 1082, 1082, 2915, 1082,
+     1082, 2915, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082,
+     1082, 1082, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1082,
+
+     2915, 1082, 1082, 2915, 1082, 1082, 2915, 1082, 1082, 2915,
+     1082, 1082, 2915, 1082, 1082, 1082, 2915, 1082, 3360, 1082,
+     1082, 1082, 2915, 1082, 1082, 1082, 1082, 1082, 1082, 2915,
+     2915, 2915, 1082, 1082, 2915, 1082, 1082, 1082, 2915, 1082,
+     2915, 1082, 1082, 2915, 1082, 1082, 1082, 1082, 1082, 1082,
+     2915, 1082, 1082, 1082, 1082, 2915, 1082, 1082, 2915, 1082,
+     2915, 2915, 1082, 2915, 1082, 1082, 1082, 1082, 1082, 1082,
+     2915, 3361, 1082, 1082, 2915, 2915, 1082, 1082, 2915, 1082,
+     3362, 3363, 3363, 3364, 3365, 3366, 3364, 3364, 3367, 3368,
+     3369, 3370, 3370, 3371, 3372, 3373, 3364, 3363, 3367, 3368,
+
+     3369, 3363, 3364, 3364, 3367, 3368, 3369, 3367, 3364, 3374,
+     3375, 3376, 3371, 3370, 3377, 3378, 3379, 3380, 3381, 3381,
+     3382, 3383, 3384, 3382, 3382, 3385, 3386, 3387, 3388, 3388,
+     3389, 3390, 3391, 3382, 3381, 3385, 3386, 3387, 3381, 3382,
+     3382, 3385, 3386, 3387, 3385, 3382, 3392, 3393, 3394, 3389,
+     3388, 3395, 3396, 3397, 2915, 2915, 2915, 3398, 3398, 1359,
+     2915, 2915, 2915, 3398, 3399, 3400, 3401, 1359, 1359, 1359,
+     2915, 3402, 2915, 1359, 2915, 1371, 1364, 3399, 3400, 3402,
+     2915, 3402, 1359, 2915, 1359, 2915, 1359, 1359, 1359, 1359,
+     1359, 1359, 1359, 2915, 1359, 1359, 1359, 1359, 2915, 1359,
+
+     1359, 2915, 2915, 2915, 1364, 3399, 3400, 3403, 3404, 1359,
+     2915, 3404, 2915, 2915, 1364, 3399, 3400, 1359, 2915, 3405,
+     2915, 1359, 2915, 1364, 3399, 3400, 1359, 2915, 1359, 1359,
+     1359, 1359, 1359, 1359, 2915, 3406, 1359, 1359, 1359, 1359,
+     2915, 1359, 1359, 1359, 1359, 2915, 1359, 1359, 1359, 2915,
+     1359, 1359, 2915, 2915, 1359, 2915, 1359, 1359, 2915, 1359,
+     1359, 2915, 1359, 2915, 1359, 1359, 2915, 2915, 1364, 3399,
+     3400, 3407, 1359, 2915, 3407, 2915, 2915, 1364, 3399, 3400,
+     1359, 2915, 1359, 1359, 1359, 2915, 1359, 1359, 1359, 1359,
+     1359, 1359, 1359, 1359, 1359, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1359, 1359,
+     2915, 1359, 1359, 1359, 2915, 1359, 1359, 2915, 1359, 1359,
+     2915, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1359, 1359, 2915, 1359, 1359,
+     2915, 1359, 2915, 1359, 2915, 1359, 2915, 1359, 1359, 3408,
+     3408, 3408, 1359, 2915, 3409, 1359, 2915, 1359, 1359, 1359,
+     1359, 1359, 2915, 2915, 2915, 1359, 1359, 1359, 2915, 2915,
+     1359, 1359, 1359, 2915, 2915, 1359, 1359, 1359, 2915, 1359,
+     2915, 1359, 1359, 2915, 1359, 1359, 1359, 1359, 2915, 1359,
+     2915, 1359, 2915, 2915, 1359, 2915, 1359, 1359, 2915, 1359,
+
+     1371, 3402, 1359, 1359, 2915, 3410, 2915, 2915, 1605, 1364,
+     3399, 3400, 3410, 3410, 1359, 1359, 2915, 2915, 1359, 1359,
+     2915, 1359, 3411, 3411, 3412, 3413, 3414, 3412, 3412, 3415,
+     3416, 3417, 3418, 3418, 3419, 3420, 3421, 3412, 3412, 3415,
+     3416, 3417, 3415, 3415, 3422, 3423, 3424, 3419, 3419, 3425,
+     3426, 3427, 3428, 3428, 3429, 3430, 3431, 3429, 3429, 3432,
+     3433, 3434, 3435, 3435, 3436, 3437, 3438, 3429, 3429, 3432,
+     3433, 3434, 3432, 3432, 3439, 3440, 3441, 3436, 3436, 3442,
+     3443, 3444, 3445, 3446, 3446, 2915, 1685, 1685, 2915, 3447,
+     2915, 3447, 3447, 1685, 2915, 1685, 2915, 1685, 2915, 1685,
+
+     1685, 2915, 1685, 1685, 2915, 1685, 1685, 2915, 1685, 1685,
+     2915, 1685, 1685, 2915, 1685, 1685, 1685, 2915, 1685, 3448,
+     3448, 3448, 2915, 2915, 1685, 1685, 2915, 1685, 1685, 1685,
+     1685, 1685, 2915, 2915, 2915, 1685, 1685, 3446, 3449, 3450,
+     3451, 2915, 2915, 1685, 1685, 2915, 1685, 1685, 1685, 2915,
+     1685, 1685, 2915, 1685, 2915, 1685, 2915, 1685, 1685, 2915,
+     1685, 1685, 2915, 2915, 1685, 2915, 2915, 1685, 2915, 1685,
+     1685, 2915, 1685, 1685, 2915, 1685, 2915, 2915, 1685, 2915,
+     1685, 1685, 2915, 2915, 2915, 3452, 1685, 1738, 1784, 3453,
+     3454, 3455, 3455, 3455, 1685, 2915, 1685, 1685, 2915, 1685,
+
+     1685, 2915, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 1685, 2915, 1685, 1685, 2915, 1685,
+     2915, 1685, 2915, 1685, 2915, 1685, 1685, 1685, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 1685,
+     2915, 1685, 2915, 1685, 1685, 2915, 2915, 1685, 2915, 1685,
+     3456, 3456, 1685, 1685, 2915, 2915, 2915, 1685, 1738, 3449,
+     3450, 3457, 2915, 1685, 2915, 1685, 1685, 2915, 1685, 1685,
+     1685, 2915, 2915, 2915, 1685, 1685, 1685, 1685, 1685, 2915,
+     2915, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915,
+     1685, 2915, 1685, 1685, 1685, 2915, 2915, 1685, 2915, 1685,
+     1685, 2915, 1685, 1689, 3447, 3447, 1685, 2915, 1685, 2915,
+     3458, 3458, 3458, 1685, 2915, 2915, 1685, 2915, 1685, 1685,
+     1685, 1685, 1685, 2915, 2915, 2915, 1685, 1685, 3447, 1685,
+     2915, 1685, 2915, 1685, 2915, 2915, 1685, 2915, 1685, 1685,
+     2915, 1685, 1685, 2915, 1685, 1685, 2915, 1685, 1685, 2915,
+     1685, 1685, 1685, 2915, 1685, 2915, 1685, 1685, 2915, 1685,
+     1685, 1685, 2915, 2915, 1685, 1685, 2915, 1685, 1685, 2915,
+     1685, 2915, 1685, 2915, 2915, 1685, 1685, 1685, 2915, 2915,
+
+     1685, 2915, 1685, 1685, 1685, 2915, 1685, 1685, 2915, 1685,
+     1784, 3452, 2915, 2915, 1738, 3449, 3450, 3452, 3452, 1784,
+     1784, 1738, 1789, 1738, 1789, 1789, 1685, 2915, 1685, 2915,
+     1685, 2915, 1685, 1685, 1685, 1685, 1685, 1685, 2915, 2915,
+     3459, 2915, 2915, 2915, 3460, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1930, 3458, 1685, 2915, 1685,
+     2915, 1685, 2915, 2915, 1685, 2915, 1685, 2915, 1685, 1685,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915,
+     1685, 1685, 2915, 1685, 1685, 2915, 2915, 1685, 2915, 1685,
+     2915, 1685, 3456, 3456, 3456, 1685, 1865, 3457, 1685, 3457,
+
+     2915, 1685, 2915, 1685, 1685, 2915, 1685, 1685, 2915, 2915,
+     1685, 1685, 1685, 1685, 2915, 2915, 1685, 1685, 1685, 1685,
+     1685, 1685, 1685, 1685, 1685, 1685, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 1685,
+     1685, 2915, 1685, 1685, 1685, 2915, 1685, 1685, 2915, 2915,
+     1685, 2915, 3458, 1685, 3447, 2915, 1685, 1685, 1685, 2915,
+     2915, 2915, 3461, 1685, 1685, 2915, 1685, 2915, 1685, 2915,
+     1685, 1956, 3462, 2915, 1956, 2915, 1738, 3449, 3450, 1685,
+     2915, 1685, 2915, 1685, 1685, 2915, 1685, 2915, 1685, 1685,
+     2915, 1685, 1685, 1685, 1685, 2915, 1685, 2915, 1685, 2915,
+
+     1685, 2915, 2915, 1685, 2915, 1685, 1685, 2915, 1685, 2915,
+     1685, 1685, 2915, 2915, 1685, 1685, 1685, 3452, 1685, 2915,
+     1685, 2915, 1685, 1685, 1685, 1685, 1685, 2915, 2915, 3459,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1930, 3458,
+     1685, 3458, 2915, 1685, 2915, 1685, 1685, 1685, 1685, 1685,
+     1685, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915,
+     1685, 1685, 2915, 2915, 1685, 2915, 2915, 1685, 1685, 1865,
+     3457, 1685, 3457, 2915, 1685, 2915, 1685, 1685, 2915, 2915,
+     1685, 1685, 1685, 2915, 1685, 1685, 2915, 1685, 2915, 2915,
+     2915, 2915, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685,
+
+     1685, 1685, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 1685, 2915, 1685, 1685, 1685, 1685, 1685, 2915, 2915,
+     1685, 3447, 3447, 2915, 1685, 1685, 2915, 3463, 3461, 1685,
+     2915, 1685, 2915, 1685, 2915, 3462, 1956, 3462, 1685, 2915,
+     1685, 2915, 1685, 2915, 1685, 1685, 2915, 1685, 1685, 1685,
+     1685, 2915, 1685, 1685, 2915, 2915, 1685, 2915, 2915, 1685,
+     2915, 1685, 1685, 2915, 1685, 2915, 1685, 1685, 2915, 2915,
+     1685, 1685, 1685, 2915, 1685, 1685, 1685, 1685, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1685,
+     2915, 1685, 1685, 1685, 1685, 1685, 1685, 2915, 2915, 2915,
+
+     1685, 2915, 1685, 1685, 2915, 2915, 1685, 1685, 1685, 2915,
+     1685, 2915, 1685, 2915, 1685, 1685, 1685, 1685, 2915, 2915,
+     1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915,
+     1685, 1685, 2915, 1685, 1685, 2915, 3464, 3463, 1685, 1685,
+     2915, 1685, 2915, 3462, 1685, 2915, 1685, 1685, 1685, 1685,
+     2915, 1685, 2915, 1685, 1685, 2915, 2915, 2915, 2915, 1685,
+     2915, 1685, 2915, 2915, 1685, 2915, 1685, 1685, 2915, 2915,
+     1685, 1685, 1685, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     1685, 2915, 1685, 1685, 1685, 1685, 1956, 3462, 2915, 1685,
+
+     1685, 2915, 2915, 1685, 1685, 1685, 2915, 1685, 2915, 2915,
+     1685, 1685, 1685, 1685, 2915, 2915, 1685, 1685, 1685, 1685,
+     1685, 1685, 1685, 1685, 1685, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 1685, 2915, 1685, 1685, 3458, 1685, 2915,
+     3464, 1685, 1685, 2915, 1685, 2915, 1685, 2915, 1685, 1685,
+     1685, 1685, 2915, 1685, 2915, 1685, 1685, 2915, 2915, 2915,
+     2915, 1685, 2915, 1685, 2915, 1685, 1685, 2915, 2915, 2915,
+     1685, 2915, 1685, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 1685, 1685, 1685, 1685, 3462, 2915, 1685, 1685, 2915,
+     2915, 2915, 1685, 1685, 1685, 2915, 1685, 1685, 2915, 1685,
+
+     1685, 1685, 1685, 1685, 1685, 1685, 1685, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915, 1685,
+     3458, 3458, 1685, 2915, 1685, 1685, 1685, 2915, 1685, 2915,
+     1685, 1685, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915,
+     1685, 2915, 1685, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 1685, 1685, 1685, 1685, 2915, 1685, 2915, 1685,
+     1685, 1685, 2915, 1685, 2915, 1685, 1685, 1685, 1685, 1685,
+     1685, 1685, 1685, 1685, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 1685, 2915, 1685, 2915, 1685, 2915, 1685, 2915,
+     1685, 2915, 1685, 2915, 1685, 1685, 2915, 2915, 1685, 2915,
+
+     1685, 2915, 1685, 2915, 2915, 1685, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915, 1685,
+     2915, 2915, 1685, 2915, 2915, 1685, 1685, 1685, 2915, 2915,
+     1685, 2915, 1685, 1685, 1685, 1685, 1685, 1685, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915,
+     1685, 2915, 1685, 2915, 2915, 3465, 1685, 1685, 2915, 2915,
+     1685, 2915, 1685, 2915, 2915, 1685, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915, 1685, 2915,
+     2915, 1685, 2915, 2915, 1685, 1685, 2915, 2915, 1685, 1685,
+     1685, 1685, 1685, 1685, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     1685, 2915, 1685, 2915, 1685, 2915, 1685, 2915, 1685, 2915,
+     2915, 1685, 2755, 3465, 2915, 2915, 2755, 1738, 3449, 3450,
+     3465, 3465, 1685, 1685, 2915, 2915, 1685, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1685, 1685, 1685, 1685, 2915,
+     2915, 2915, 2915, 2915, 2915, 1685, 2915, 1685, 2915, 2915,
+     2755, 3465, 3465, 1685, 1685, 2915, 2915, 2915, 2915, 2915,
+     2915, 1685, 1685, 1685, 2915, 2915, 2915, 1685, 2915, 1685,
+     2915, 2915, 2915, 1685, 1685, 1685, 2915, 2915, 1685, 2915,
+     1685, 2915, 2915, 2915, 1685, 1685, 1685, 2915, 2915, 1685,
+     2915, 2915, 2915, 1685, 1685, 2915, 2915, 1685, 2915, 2915,
+
+     2915, 2915, 1685, 2915, 2915, 1685, 2915, 2915, 1685, 2915,
+     2915, 1685, 2915, 2915,    0, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915
+    } ;
+
+static yyconst flex_int16_t yy_nxt[27006] =
+    {   0,
+     2915,  125,  126,  717,  127,  128,  129,  717,  129,  130,
+      131,  132,  130,  133,  134,  129,  130,  129,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,
+      130,  124,  130,  130,  130,  135,  136,  137,  138,  139,
+      140,  130,  141,  142,  130,  143,  144,  145,  146,  147,
+      148,  149,  150,  151,  152,  153,  154,  130,  130,  155,
+      130,  130,  124,  124,  124,  124,  124,  124,  124,  124,
+      124,  124,  124,  124,  124,  124,  124,  124,  124,  124,
+      124,  156,  156,  156,  156,  156,  156,  157,  157,  157,
+      158,  124,  124,  159,  159,  160,  159,  161,  162,  163,
+
+      164,  163,  159,  165,  159,  159,  159,  159,  159,  159,
+      166,  159,  159,  167,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+      159,  159,  159,  159,  168,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  170,  170,  170,  170,  170,
+      170,  171,  171,  171,  172,  169,  169,  173,  169,  174,
+      173,  175,  176,  173,  173,  173,  173,  173,  173,  169,
+      173,  173,  173,  173,  173,  173,  173,  177,  173,  173,
+
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      177,  177,  177,  177,  177,  177,  177,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  177,  177,  177,  178,
+      178,  178,  178,  178,  178,  179,  179,  179,  180,  177,
+      177,  181,  509,  182,  176,  181,  510,  182,  176,  183,
+      183,  181,  183,  182,  184,  183,  183,  183,  183,  183,
+      183,  183,  183,  183,  183,  183,  183,  183,  183,  183,
+      183,  183,  183,  183,  183,  183,  183,  183,  183,  183,
+
+      183,  183,  183,  183,  183,  183,  183,  183,  183,  183,
+      183,  183,  183,  183,  183,  183,  183,  183,  183,  183,
+      183,  183,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  185,  185,  185,  185,  185,  185,  186,  186,  186,
+      187,  169,  169,  188,  188,  181,  188,  182,  189,  188,
+      188,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+      188,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+      188,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+      188,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+
+      188,  188,  188,  188,  188,  188,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  190,  190,  190,  190,  190,
+      190,  191,  191,  191,  192,  169,  169,  193,  193,  194,
+      193,  195,  196,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      197,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      198,  198,  198,  198,  198,  198,  198,  198,  198,  198,
+
+      198,  198,  198,  198,  198,  198,  198,  198,  198,  199,
+      199,  199,  199,  199,  199,  200,  200,  200,  201,  198,
+      198,  202,  202,  181,  202,  182,  203,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      202,  202,  202,  202,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  204,  204,  204,  204,  204,  204,  205,
+
+      205,  205,  206,  169,  169,  207,  207,  181,  207,  182,
+      208,  207,  207,  207,  207,  207,  207,  207,  207,  207,
+      207,  207,  207,  207,  207,  207,  207,  207,  207,  207,
+      207,  207,  207,  207,  207,  207,  207,  207,  207,  207,
+      207,  207,  207,  207,  207,  207,  207,  207,  207,  207,
+      207,  207,  207,  207,  207,  207,  207,  207,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  209,  209,  209,
+      209,  209,  209,  210,  210,  210,  211,  169,  169,  212,
+      212,  181,  212,  182,  213,  212,  212,  212,  212,  212,
+
+      212,  212,  212,  212,  212,  212,  212,  212,  212,  212,
+      212,  212,  212,  212,  212,  212,  212,  212,  212,  212,
+      212,  212,  212,  212,  212,  212,  212,  212,  212,  212,
+      212,  212,  212,  212,  212,  212,  212,  212,  212,  212,
+      212,  212,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  214,  214,  214,  214,  214,  214,  215,  215,  215,
+      216,  169,  169,  217,  217,  181,  217,  182,  218,  217,
+      217,  217,  217,  217,  217,  217,  217,  217,  217,  217,
+      217,  217,  217,  217,  217,  217,  217,  217,  217,  217,
+
+      217,  217,  217,  217,  217,  217,  217,  217,  217,  217,
+      217,  217,  217,  217,  217,  217,  217,  217,  217,  217,
+      217,  217,  217,  217,  217,  217,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  219,  219,  219,  219,  219,
+      219,  220,  220,  220,  221,  169,  169,  222,  222,  181,
+      222,  182,  223,  222,  222,  222,  222,  222,  222,  222,
+      222,  222,  222,  222,  222,  222,  222,  222,  222,  222,
+      222,  222,  222,  222,  222,  222,  222,  222,  222,  222,
+      222,  222,  222,  222,  222,  222,  222,  222,  222,  222,
+
+      222,  222,  222,  222,  222,  222,  222,  222,  222,  222,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  224,
+      224,  224,  224,  224,  224,  225,  225,  225,  226,  169,
+      169,  227,  227,  181,  227,  182,  228,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  169,  169,  169,  169,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  229,  229,  229,  229,  229,  229,  230,
+      230,  230,  231,  169,  169,  232,  232,  181,  232,  182,
+      233,  232,  232,  232,  232,  232,  232,  232,  232,  232,
+      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
+      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
+      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
+      232,  232,  232,  232,  232,  232,  232,  232,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  234,  234,  234,
+
+      234,  234,  234,  235,  235,  235,  236,  169,  169,  237,
+      237,  181,  237,  182,  238,  237,  237,  237,  237,  237,
+      237,  237,  237,  237,  237,  237,  237,  237,  237,  237,
+      237,  237,  237,  237,  237,  237,  237,  237,  237,  237,
+      237,  237,  237,  237,  237,  237,  237,  237,  237,  237,
+      237,  237,  237,  237,  237,  237,  237,  237,  237,  237,
+      237,  237,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  239,  239,  239,  239,  239,  239,  240,  240,  240,
+      241,  169,  169,  242,  242,  181,  242,  182,  243,  242,
+
+      242,  242,  242,  242,  242,  242,  242,  242,  242,  242,
+      242,  242,  242,  242,  242,  242,  242,  242,  242,  242,
+      242,  242,  242,  242,  242,  242,  242,  242,  242,  242,
+      242,  242,  242,  242,  242,  242,  242,  242,  242,  242,
+      242,  242,  242,  242,  242,  242,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  244,  244,  244,  244,  244,
+      244,  245,  245,  245,  246,  169,  169,  247,  247,  181,
+      247,  182,  248,  247,  247,  247,  247,  247,  247,  247,
+      247,  247,  247,  247,  247,  247,  247,  247,  247,  247,
+
+      247,  247,  247,  247,  247,  247,  247,  247,  247,  247,
+      247,  247,  247,  247,  247,  247,  247,  247,  247,  247,
+      247,  247,  247,  247,  247,  247,  247,  247,  247,  247,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  249,
+      249,  249,  249,  249,  249,  250,  250,  250,  251,  169,
+      169,  252,  252,  181,  252,  182,  253,  252,  252,  252,
+      252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
+      252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
+      252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
+
+      252,  252,  252,  252,  252,  252,  252,  252,  252,  252,
+      252,  252,  252,  252,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  254,  254,  254,  254,  254,  254,  255,
+      255,  255,  256,  169,  169,  258,  511,  259,  176,  258,
+      512,  259,  176,  181,  509,  261,  176,  181,  510,  261,
+      176,  262,  262,  181,  262,  182,  263,  262,  262,  262,
+      262,  262,  262,  262,  262,  262,  262,  262,  262,  262,
+      262,  262,  262,  262,  262,  262,  262,  262,  262,  262,
+      262,  262,  262,  262,  262,  262,  262,  262,  262,  262,
+
+      262,  262,  262,  262,  262,  262,  262,  262,  262,  262,
+      262,  262,  262,  262,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  264,  264,  264,  264,  264,  264,  265,
+      265,  265,  266,  169,  169,  267,  267,  181,  267,  182,
+      268,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  267,  267,  267,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  269,  269,  269,
+      269,  269,  269,  270,  270,  270,  271,  169,  169,  272,
+      272,  181,  272,  182,  273,  272,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  272,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+
+      169,  274,  274,  274,  274,  274,  274,  275,  275,  275,
+      276,  169,  169,  277,  277,  181,  277,  182,  278,  277,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  277,  277,  277,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  279,  279,  279,  279,  279,
+      279,  280,  280,  280,  281,  169,  169,  181,  726,  283,
+
+      284,  181,  511,  283,  284,  286,  512,  287,  288,  286,
+      289,  287,  288,  291,  289,  292,  293,  291,  480,  292,
+      293,  181,  481,  182,  176,  181,  726,  182,  176,  492,
+      317,  315,  318,  319,  317,  315,  318,  319,  493, 2915,
+      542,  169,  543,  169,  922,  169,  181,  169,  182,  176,
+      181,  923,  182,  176,  503,  169,  361,  320,  362,  176,
+      504,  320,  181,  294,  182,  176, 2915,  294,  295,  295,
+      181,  295,  182,  296,  295,  295,  295,  295,  295,  295,
+      295,  295,  295,  295,  295,  295,  295,  295,  295,  295,
+      295,  295,  295,  295,  295,  295,  295,  295,  295,  295,
+
+      295,  295,  295,  295,  295,  295,  295,  295,  295,  295,
+      295,  295,  295,  295,  295,  295,  295,  295,  295,  295,
+      295,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      297,  297,  297,  297,  297,  297,  298,  298,  298,  299,
+      169,  169,  300,  300,  181,  300,  182,  301,  300,  300,
+      300,  300,  300,  300,  300,  300,  300,  300,  300,  300,
+      300,  300,  300,  300,  300,  300,  300,  300,  300,  300,
+      300,  300,  300,  300,  300,  300,  300,  300,  300,  300,
+      300,  300,  300,  300,  300,  300,  300,  300,  300,  300,
+
+      300,  300,  300,  300,  300,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  302,  302,  302,  302,  302,  302,
+      303,  303,  303,  304,  169,  169,  305,  305,  181,  305,
+      182,  306,  305,  305,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  305,  305,  305,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  307,  307,
+      307,  307,  307,  307,  308,  308,  308,  309,  169,  169,
+      310,  310,  181,  310,  182,  311,  310,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,  310,  310,  310,  310,
+      310,  310,  310,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  312,  312,  312,  312,  312,  312,  313,  313,
+
+      313,  314,  169,  169,  321,  321,  181,  321,  322,  323,
+      321,  324,  321,  321,  325,  326,  321,  321,  321,  321,
+      321,  327,  326,  326,  328,  321,  326,  321,  326,  321,
+      326,  326,  326,  326,  326,  326,  326,  326,  326,  326,
+      326,  326,  326,  326,  326,  326,  326,  326,  326,  326,
+      326,  326,  326,  326,  326,  329,  321,  321,  321,  321,
+      321,  321,  321,  321,  321,  321,  321,  321,  321,  321,
+      321,  321,  321,  321,  321,  321,  330,  331,  332,  333,
+      334,  335,  336,  337,  338,  339,  321,  321,  340,  340,
+      181,  340,  182,  341,  340,  340,  340,  340,  340,  340,
+
+      340,  340,  340,  340,  340,  340,  340,  340,  340,  340,
+      340,  340,  340,  340,  340,  340,  340,  340,  340,  340,
+      340,  340,  340,  340,  340,  340,  340,  340,  340,  340,
+      340,  340,  340,  340,  340,  340,  340,  340,  340,  340,
+      340,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      342,  342,  342,  342,  342,  342,  343,  343,  343,  344,
+      169,  169,  345,  345,  181,  345,  182,  346,  345,  345,
+      345,  345,  345,  345,  345,  345,  345,  345,  345,  345,
+      345,  345,  345,  345,  345,  345,  345,  345,  345,  345,
+
+      345,  345,  345,  345,  345,  345,  345,  345,  345,  345,
+      345,  345,  345,  345,  345,  345,  345,  345,  345,  345,
+      345,  345,  345,  345,  345,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  347,  347,  347,  347,  347,  347,
+      348,  348,  348,  349,  169,  169,  350,  350,  181,  350,
+      182,  351,  350,  350,  350,  350,  350,  350,  350,  350,
+      350,  350,  350,  350,  350,  350,  350,  350,  350,  350,
+      350,  350,  350,  350,  350,  350,  350,  350,  350,  350,
+      350,  350,  350,  350,  350,  350,  350,  350,  350,  350,
+
+      350,  350,  350,  350,  350,  350,  350,  350,  350,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  352,  352,
+      352,  352,  352,  352,  353,  353,  353,  354,  169,  169,
+      355,  355,  181,  355,  182,  356,  355,  355,  355,  355,
+      355,  355,  355,  355,  355,  355,  355,  355,  355,  355,
+      355,  355,  355,  355,  355,  355,  355,  355,  355,  355,
+      355,  355,  355,  355,  355,  355,  355,  355,  355,  355,
+      355,  355,  355,  355,  355,  355,  355,  355,  355,  355,
+      355,  355,  355,  169,  169,  169,  169,  169,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  357,  357,  357,  357,  357,  357,  358,  358,
+      358,  359,  169,  169,  169,  361,  726,  362,  176,  364,
+      365,  492,  366,  367,  364,  365,  872,  366,  367,  181,
+      493,  182,  176,  169,  374,  873,  375,  176,  503,  169,
+      374,  364,  375,  176,  504,  726,  364,  368,  368,  181,
+      368,  182,  369,  368,  368,  368,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  368,  368,  368,  368,
+
+      368,  368,  368,  368,  368,  368,  368,  368,  368,  368,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  370,
+      370,  370,  370,  370,  370,  371,  371,  371,  372,  169,
+      169,  181, 2914,  182,  176,  181,  583,  182,  176,  169,
+      383,  583,  384,  176,  169,  383,  482,  384,  176,  483,
+      875,  876,  484,  485,  486,  488,  489,  593,  490,  869,
+      376,  491,  595,  870,  376,  377,  377,  181,  377,  182,
+      378,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+      377,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+
+      377,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+      377,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+      377,  377,  377,  377,  377,  377,  377,  377,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  379,  379,  379,
+      379,  379,  379,  380,  380,  380,  381,  169,  169,  181,
+     2913,  182,  176,  181,  494,  182,  176,  545,  181,  452,
+      182,  176,  495,  452,  505,  893,  882,  496,  506,  883,
+      546,  547,  507,  548,  497,  928,  501,  508,  385,  408,
+      453,  929,  385,  386,  386,  181,  386,  182,  387,  386,
+
+      386,  386,  386,  386,  386,  386,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  386,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  386,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  386,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  386,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  388,  388,  388,  388,  388,
+      388,  389,  389,  389,  390,  169,  169,  391,  391,  181,
+      391,  182,  392,  391,  391,  391,  391,  391,  391,  391,
+      391,  391,  391,  391,  391,  391,  391,  391,  391,  391,
+
+      391,  391,  391,  391,  391,  391,  391,  391,  391,  391,
+      391,  391,  391,  391,  391,  391,  391,  391,  391,  391,
+      391,  391,  391,  391,  391,  391,  391,  391,  391,  391,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  393,
+      393,  393,  393,  393,  393,  394,  394,  394,  395,  169,
+      169,  396,  396,  181,  396,  182,  397,  396,  396,  396,
+      396,  396,  396,  396,  396,  396,  396,  396,  396,  396,
+      396,  396,  396,  396,  396,  396,  396,  396,  396,  396,
+      396,  396,  396,  396,  396,  396,  396,  396,  396,  396,
+
+      396,  396,  396,  396,  396,  396,  396,  396,  396,  396,
+      396,  396,  396,  396,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  398,  398,  398,  398,  398,  398,  399,
+      399,  399,  400,  169,  169,  401,  401,  402,  401,  403,
+      404,  401,  401,  401,  401,  401,  401,  401,  401,  401,
+      401,  401,  401,  401,  401,  401,  401,  401,  401,  401,
+      401,  401,  401,  401,  401,  401,  401,  401,  401,  401,
+      401,  401,  401,  401,  401,  401,  401,  401,  401,  401,
+      401,  401,  401,  401,  401,  401,  401,  401,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  405,  405,  405,
+      405,  405,  405,  406,  406,  406,  407,  169,  169,  181,
+      499,  182,  176,  542, 2911,  543,  500,  553,  553,  553,
+      553,  553,  553,  554,  554,  554,  555,  501, 2910,  502,
+      408,  409,  409,  181,  409,  182,  410,  409,  409,  409,
+      409,  409,  409,  409,  409,  409,  409,  409,  409,  409,
+      409,  409,  409,  409,  409,  409,  409,  409,  409,  409,
+      409,  409,  409,  409,  409,  409,  409,  409,  409,  409,
+      409,  409,  409,  409,  409,  409,  409,  409,  409,  409,
+
+      409,  409,  409,  409,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  411,  411,  411,  411,  411,  411,  412,
+      412,  412,  413,  169,  169,  414,  414,  181,  414,  182,
+      415,  414,  414,  414,  414,  414,  414,  414,  414,  414,
+      414,  414,  414,  414,  414,  414,  414,  414,  414,  414,
+      414,  414,  414,  414,  414,  414,  414,  414,  414,  414,
+      414,  414,  414,  414,  414,  414,  414,  414,  414,  414,
+      414,  414,  414,  414,  414,  414,  414,  414,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  416,  416,  416,
+      416,  416,  416,  417,  417,  417,  418,  169,  169,  419,
+      419,  181,  419,  182,  420,  419,  419,  419,  419,  419,
+      419,  419,  419,  419,  419,  419,  419,  419,  419,  419,
+      419,  419,  419,  419,  419,  419,  419,  419,  419,  419,
+      419,  419,  419,  419,  419,  419,  419,  419,  419,  419,
+      419,  419,  419,  419,  419,  419,  419,  419,  419,  419,
+      419,  419,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  421,  421,  421,  421,  421,  421,  422,  422,  422,
+
+      423,  169,  169,  424,  424,  181,  424,  182,  425,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,  424,  424,  424,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  426,  426,  426,  426,  426,
+      426,  427,  427,  427,  428,  169,  169,  429,  429,  181,
+      429,  182,  430,  429,  429,  429,  429,  429,  429,  429,
+
+      429,  429,  429,  429,  429,  429,  429,  429,  429,  429,
+      429,  429,  429,  429,  429,  429,  429,  429,  429,  429,
+      429,  429,  429,  429,  429,  429,  429,  429,  429,  429,
+      429,  429,  429,  429,  429,  429,  429,  429,  429,  429,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  431,
+      431,  431,  431,  431,  431,  432,  432,  432,  433,  169,
+      169,  434,  434,  181,  434,  182,  435,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,  434,
+      434,  434,  434,  434,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  436,  436,  436,  436,  436,  436,  437,
+      437,  437,  438,  169,  169,  439,  439,  181,  439,  182,
+      440,  439,  439,  439,  439,  439,  439,  439,  439,  439,
+      439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
+      439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
+      439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
+
+      439,  439,  439,  439,  439,  439,  439,  439,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  441,  441,  441,
+      441,  441,  441,  442,  442,  442,  443,  169,  169,  444,
+      444,  181,  444,  182,  445,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  169,  169,  169,  169,  169,  169,  169,  169,
+
+      169,  169,  169,  169,  169,  169,  169,  169,  169,  169,
+      169,  446,  446,  446,  446,  446,  446,  447,  447,  447,
+      448,  169,  169,  451,  514,  520,  714,  452,  726,  521,
+      865,  897,  866,  898,  715,  910,  716,  515,  522,  523,
+      516,  517,  524,  518,  453,  726,  525,  911,  903,  526,
+      527,  488,  489,  956,  490,  528,  529,  491,  957,  530,
+      531,  532,  534,  535,  714,  533,  536,  900,  537,  904,
+      538,  901,  715,  938,  716,  539,  939,  540, 2908,  541,
+      571,  571,  571,  571,  571,  571,  572,  572,  572,  573,
+     2915,  984, 2907,  985,  454,  454,  454,  454,  454,  454,
+
+      455,  455,  455,  456,  450,  457,  450,  450,  450,  458,
+     2915,  450, 2905,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  453,  450,  450,  450,
+      459,  460,  461,  462,  463,  464,  450,  465,  466,  450,
+      467,  468,  469,  470,  471,  472,  473,  474,  475,  476,
+      477,  478,  450,  450,  479,  450,  450,  571,  571,  571,
+      571,  571,  571,  572,  572,  572,  573,  482,  480,  584,
+      483, 2904,  481,  484,  485,  486,  454,  454,  454,  454,
+      454,  454,  455,  455,  455,  456,  451,  942,  545, 2915,
+      452,  577,  577,  577,  577,  577,  577,  578,  578,  578,
+
+      579,  546,  547,  450,  548,  943, 1249,  453,  577,  577,
+      577,  577,  577,  577,  578,  578,  578,  579,  589,  589,
+      589,  589,  589,  589,  590,  590,  590,  591,  597,  597,
+      597,  597,  597,  597,  598,  598,  598,  599,  597,  597,
+      597,  597,  597,  597,  598,  598,  598,  599,  940,  949,
+      971,  583,  958,  950,  941,  972, 2902,  454,  454,  454,
+      454,  454,  454,  455,  455,  455,  456, 2915,  959,  450,
+     1107,  450,  593,  450,  603,  603,  603,  603,  603,  603,
+      604,  604,  604,  605,  603,  603,  603,  603,  603,  603,
+      604,  604,  604,  605,  609,  609,  609,  609,  609,  609,
+
+      610,  610,  610,  611,  609,  609,  609,  609,  609,  609,
+      610,  610,  610,  611, 1083,  450,  450, 1096,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  615,  615,  615,
+      615,  615,  615,  616,  616,  616,  617,  450,  450,  560,
+      561,  562,  560,  560,  561,  560,  560,  560,  560,  560,
+      560,  563,  560,  560,  560,  560,  560,  560,  560,  564,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+
+      560,  560,  562,  562,  562,  562,  562,  562,  562,  562,
+      562,  562,  562,  562,  562,  562,  562,  562,  562,  562,
+      562,  565,  565,  565,  565,  565,  565,  566,  566,  566,
+      567,  562,  562,  563,  615,  615,  615,  615,  615,  615,
+      616,  616,  616,  617,  621,  621,  621,  621,  621,  621,
+      622,  622,  622,  623,  621,  621,  621,  621,  621,  621,
+      622,  622,  622,  623,  627,  627,  627,  627,  627,  627,
+      628,  628,  628,  629,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  568,  568,  568,  568,  568,  568,  568,
+
+      568,  568,  568,  568,  568,  568,  568,  568,  568,  568,
+      568,  568,  569,  569,  569,  569,  569,  569,  569,  569,
+      569,  569,  569,  569,  569,  569,  569,  569,  569,  569,
+      569,  570,  627,  627,  627,  627,  627,  627,  628,  628,
+      628,  629,  633,  633,  633,  633,  633,  633,  634,  634,
+      634,  635,  633,  633,  633,  633,  633,  633,  634,  634,
+      634,  635,  639,  639,  639,  639,  639,  639,  640,  640,
+      640,  641,  962,  717, 1082, 1108,  450,  717,  450,  963,
+      570,  570,  570,  570,  570,  570,  570,  570,  570,  570,
+      570,  570,  570,  570,  570,  570,  570,  570,  570,  639,
+
+      639,  639,  639,  639,  639,  640,  640,  640,  641,  570,
+      570,  576,  645,  645,  645,  645,  645,  645,  646,  646,
+      646,  647,  645,  645,  645,  645,  645,  645,  646,  646,
+      646,  647,  651,  651,  651,  651,  651,  651,  652,  652,
+      652,  653,  651,  651,  651,  651,  651,  651,  652,  652,
+      652,  653,  450,  450, 1109,  450, 1177, 1094,  450, 1095,
+      576,  576,  576,  576,  576,  576,  576,  576,  576,  576,
+      576,  576,  576,  576,  576,  576,  576,  576,  576,  657,
+      657,  657,  657,  657,  657,  658,  658,  658,  659,  576,
+      576,  582,  582,  583,  582,  583,  582,  582,  582,  582,
+
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  584,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  583,  583,  583,  583,  583,  583,
+      583,  583,  583,  583,  583,  583,  583,  583,  583,  583,
+      583,  583,  583,  585,  585,  585,  585,  585,  585,  586,
+      586,  586,  587,  583,  583,  582,  657,  657,  657,  657,
+      657,  657,  658,  658,  658,  659,  907,  912,  988,  450,
+      908,  913,  989, 1111,  588,  665,  665,  665,  665,  665,
+
+      665,  666,  666,  666,  667,  665,  665,  665,  665,  665,
+      665,  666,  666,  666,  667, 1087,  914,  450, 1110,  450,
+     1118,  990,  909,  450,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  596,  671,  671,  671,  671,
+      671,  671,  672,  672,  672,  673,  671,  671,  671,  671,
+      671,  671,  672,  672,  672,  673,  677,  677,  677,  677,
+      677,  677,  678,  678,  678,  679,  677,  677,  677,  677,
+      677,  677,  678,  678,  678,  679,  450,  450,  450, 1225,
+
+      450, 1098,  984,  871,  596,  596,  596,  596,  596,  596,
+      596,  596,  596,  596,  596,  596,  596,  596,  596,  596,
+      596,  596,  596,  683,  683,  683,  683,  683,  683,  684,
+      684,  684,  685,  596,  596,  602,  683,  683,  683,  683,
+      683,  683,  684,  684,  684,  685,  690,  690,  690,  690,
+      690,  690,  691,  691,  691,  692,  690,  690,  690,  690,
+      690,  690,  691,  691,  691,  692,  696,  696,  696,  696,
+      696,  696,  697,  697,  697,  698,  450,  450,  450, 1453,
+     1453, 1155, 1124, 1254,  602,  602,  602,  602,  602,  602,
+      602,  602,  602,  602,  602,  602,  602,  602,  602,  602,
+
+      602,  602,  602,  696,  696,  696,  696,  696,  696,  697,
+      697,  697,  698,  602,  602,  608,  702,  702,  702,  702,
+      702,  702,  703,  703,  703,  704,  702,  702,  702,  702,
+      702,  702,  703,  703,  703,  704,  708,  708,  708,  708,
+      708,  708,  709,  709,  709,  710,  708,  708,  708,  708,
+      708,  708,  709,  709,  709,  710,  991, 1219, 2901, 1385,
+      992,  450,  583,  583,  608,  608,  608,  608,  608,  608,
+      608,  608,  608,  608,  608,  608,  608,  608,  608,  608,
+      608,  608,  608,  595, 1003,  450,  450,  726,  714, 2899,
+      450,  871, 1185,  608,  608,  614,  715,  993,  716,  719,
+
+      719,  719,  719,  719,  719,  720,  720,  720,  721,  723,
+      723,  723,  723,  723,  723,  724,  724,  724,  725,  727,
+      728,  729,  730,  731,  732,  733,  734,  735,  736,  739,
+      739,  739,  739,  739,  739,  740,  740,  740,  741, 2915,
+     2915, 1388, 2897,  450,  614,  614,  614,  614,  614,  614,
+      614,  614,  614,  614,  614,  614,  614,  614,  614,  614,
+      614,  614,  614,  754,  754,  754,  754,  754,  754,  755,
+      755,  755,  756,  614,  614,  620,  754,  754,  754,  754,
+      754,  754,  755,  755,  755,  756,  760,  760,  760,  760,
+      760,  760,  761,  761,  761,  762,  760,  760,  760,  760,
+
+      760,  760,  761,  761,  761,  762,  766,  766,  766,  766,
+      766,  766,  767,  767,  767,  768,  450,  450,  450, 1444,
+     1429,  450, 1247, 1248,  620,  620,  620,  620,  620,  620,
+      620,  620,  620,  620,  620,  620,  620,  620,  620,  620,
+      620,  620,  620,  766,  766,  766,  766,  766,  766,  767,
+      767,  767,  768,  620,  620,  626,  772,  772,  772,  772,
+      772,  772,  773,  773,  773,  774,  772,  772,  772,  772,
+      772,  772,  773,  773,  773,  774,  780,  780,  780,  780,
+      780,  780,  781,  781,  781,  782,  780,  780,  780,  780,
+      780,  780,  781,  781,  781,  782,  450,  450, 1356, 1461,
+
+     1268,  450, 1356, 1269,  626,  626,  626,  626,  626,  626,
+      626,  626,  626,  626,  626,  626,  626,  626,  626,  626,
+      626,  626,  626,  788,  788,  788,  788,  788,  788,  789,
+      789,  789,  790,  626,  626,  632,  788,  788,  788,  788,
+      788,  788,  789,  789,  789,  790,  796,  796,  796,  796,
+      796,  796,  797,  797,  797,  798,  796,  796,  796,  796,
+      796,  796,  797,  797,  797,  798,  802,  802,  802,  802,
+      802,  802,  803,  803,  803,  804, 1357, 1430,  450,  450,
+     1357, 1571,  450, 1443,  632,  632,  632,  632,  632,  632,
+      632,  632,  632,  632,  632,  632,  632,  632,  632,  632,
+
+      632,  632,  632,  802,  802,  802,  802,  802,  802,  803,
+      803,  803,  804,  632,  632,  638,  808,  808,  808,  808,
+      808,  808,  809,  809,  809,  810,  808,  808,  808,  808,
+      808,  808,  809,  809,  809,  810,  818,  818,  818,  818,
+      818,  818,  819,  819,  819,  820,  818,  818,  818,  818,
+      818,  818,  819,  819,  819,  820, 1432, 1433, 1481, 1517,
+      450,  450,  450,  450,  638,  638,  638,  638,  638,  638,
+      638,  638,  638,  638,  638,  638,  638,  638,  638,  638,
+      638,  638,  638,  824,  824,  824,  824,  824,  824,  825,
+      825,  825,  826,  638,  638,  644,  824,  824,  824,  824,
+
+      824,  824,  825,  825,  825,  826,  830,  830,  830,  830,
+      830,  830,  831,  831,  831,  832,  830,  830,  830,  830,
+      830,  830,  831,  831,  831,  832,  839,  839,  839,  839,
+      839,  839,  840,  840,  840,  841,  450,  450, 1525, 1527,
+      450,  450, 1460, 1434,  644,  644,  644,  644,  644,  644,
+      644,  644,  644,  644,  644,  644,  644,  644,  644,  644,
+      644,  644,  644,  839,  839,  839,  839,  839,  839,  840,
+      840,  840,  841,  644,  644,  650,  845,  845,  845,  845,
+      845,  845,  846,  846,  846,  847,  845,  845,  845,  845,
+      845,  845,  846,  846,  846,  847,  851,  851,  851,  851,
+
+      851,  851,  852,  852,  852,  853,  851,  851,  851,  851,
+      851,  851,  852,  852,  852,  853,  726,  726, 1500, 1528,
+     2896,  450, 1501,  726,  650,  650,  650,  650,  650,  650,
+      650,  650,  650,  650,  650,  650,  650,  650,  650,  650,
+      650,  650,  650,  857,  857,  857,  857,  857,  857,  858,
+      858,  858,  859,  650,  650,  656,  857,  857,  857,  857,
+      857,  857,  858,  858,  858,  859,  494,  505,  863, 2893,
+      499,  506,  521, 1127,  495,  507,  500,  514, 2915,  496,
+      508,  522,  450,  887,  924, 2915,  497,  501,  925,  502,
+      862,  888,  726,  516,  517,  878,  518,  889,  450,  879,
+
+      726,  890,  891, 1487,  656,  656,  656,  656,  656,  656,
+      656,  656,  656,  656,  656,  656,  656,  656,  656,  656,
+      656,  656,  656,  524,  917,  880,  926,  525,  918, 1097,
+      526,  527, 2892,  656,  656,  664,  528,  529,  881,  450,
+      530,  531,  532,  534,  535,  714,  533,  536, 2891,  537,
+      561,  538, 1184,  715,  561,  716,  539,  919,  540, 1093,
+      541,  450,  920,  944,  714, 2915,  953,  945,  921,  998,
+      954,  450,  715, 1084,  716,  965,  450, 1085,  930,  966,
+     2889,  450,  931, 1490,  664,  664,  664,  664,  664,  664,
+      664,  664,  664,  664,  664,  664,  664,  664,  664,  664,
+
+      664,  664,  664,  932,  946,  584, 1252,  947,  955,  933,
+      450, 1086,  967,  664,  664,  670,  968, 1117,  450,  969,
+     1549, 2888,  450,  934,  571,  571,  571,  571,  571,  571,
+      572,  572,  572,  573,  577,  577,  577,  577,  577,  577,
+      578,  578,  578,  579, 1119, 1123,  450,  584, 1561, 2884,
+      450, 1524,  450,  450,  589,  589,  589,  589,  589,  589,
+      590,  590,  590,  591,  670,  670,  670,  670,  670,  670,
+      670,  670,  670,  670,  670,  670,  670,  670,  670,  670,
+      670,  670,  670,  597,  597,  597,  597,  597,  597,  598,
+      598,  598,  599,  670,  670,  676,  589,  589,  589,  589,
+
+      589,  589,  590,  590,  590,  591,  603,  603,  603,  603,
+      603,  603,  604,  604,  604,  605,  609,  609,  609,  609,
+      609,  609,  610,  610,  610,  611,  615,  615,  615,  615,
+      615,  615,  616,  616,  616,  617,  450, 1491, 1567, 2883,
+      450, 1492, 1448,  450,  676,  676,  676,  676,  676,  676,
+      676,  676,  676,  676,  676,  676,  676,  676,  676,  676,
+      676,  676,  676,  621,  621,  621,  621,  621,  621,  622,
+      622,  622,  623,  676,  676,  682,  627,  627,  627,  627,
+      627,  627,  628,  628,  628,  629,  633,  633,  633,  633,
+      633,  633,  634,  634,  634,  635,  639,  639,  639,  639,
+
+      639,  639,  640,  640,  640,  641,  645,  645,  645,  645,
+      645,  645,  646,  646,  646,  647,  514,  863,  450, 1620,
+     1586,  450,  450,  450,  682,  682,  682,  682,  682,  682,
+      682,  682,  682,  682,  682,  682,  682,  682,  682,  682,
+      682,  682,  682,  651,  651,  651,  651,  651,  651,  652,
+      652,  652,  653,  682,  682,  689,  657,  657,  657,  657,
+      657,  657,  658,  658,  658,  659,  665,  665,  665,  665,
+      665,  665,  666,  666,  666,  667,  671,  671,  671,  671,
+      671,  671,  672,  672,  672,  673,  677,  677,  677,  677,
+      677,  677,  678,  678,  678,  679,  450, 1570, 1356, 1593,
+
+     1593, 1570, 1356,  546,  689,  689,  689,  689,  689,  689,
+      689,  689,  689,  689,  689,  689,  689,  689,  689,  689,
+      689,  689,  689,  683,  683,  683,  683,  683,  683,  684,
+      684,  684,  685,  689,  689,  695,  690,  690,  690,  690,
+      690,  690,  691,  691,  691,  692,  696,  696,  696,  696,
+      696,  696,  697,  697,  697,  698,  702,  702,  702,  702,
+      702,  702,  703,  703,  703,  704,  708,  708,  708,  708,
+      708,  708,  709,  709,  709,  710, 1023, 1559, 1357, 2134,
+     2880, 2135, 1357,  450,  695,  695,  695,  695,  695,  695,
+      695,  695,  695,  695,  695,  695,  695,  695,  695,  695,
+
+      695,  695,  695,  727,  728,  729,  730,  731,  732,  733,
+      734,  735,  736,  695,  695,  701,  754,  754,  754,  754,
+      754,  754,  755,  755,  755,  756,  718, 1125, 1262, 1237,
+     1126, 1025,  879,  583, 2149, 2149,  879,  450,  450,  450,
+      450,  719,  719,  719,  719,  719,  719,  720,  720,  720,
+      721,  718, 1215,  453,  588,  451, 1030, 1359, 2878,  452,
+      450,  450,  738, 1042,  701,  701,  701,  701,  701,  701,
+      701,  701,  701,  701,  701,  701,  701,  701,  701,  701,
+      701,  701,  701,  739,  739,  739,  739,  739,  739,  740,
+      740,  740,  741,  701,  701,  707, 1026, 1026, 1026, 1026,
+
+     1026, 1026, 1027, 1027, 1027, 1028,  718, 1226,  450,  450,
+     1242, 1035, 1044, 1220, 2877,  450,  738, 1267, 1221,  450,
+      450, 1031, 1031, 1031, 1031, 1031, 1031, 1032, 1032, 1032,
+     1033, 1523, 1045, 1045, 1045, 1045, 1045, 1045, 1046, 1046,
+     1046, 1047,  726, 2873,  707,  707,  707,  707,  707,  707,
+      707,  707,  707,  707,  707,  707,  707,  707,  707,  707,
+      707,  707,  707,  869,  878,  878, 1049,  870,  879,  879,
+     2776, 2776, 2872,  707,  707,  744, 1036, 1036, 1036, 1036,
+     1036, 1036, 1037, 1037, 1037, 1038, 1050, 1050, 1050, 1050,
+     1050, 1050, 1051, 1051, 1051, 1052,  738,  726, 1099,  450,
+
+      450,  450,  450,  451, 1091,  450, 2915,  452, 2915, 2915,
+     1396, 2915,  745,  746,  746, 1369,  747,  748,  749,  750,
+      750,  750,  750,  750,  750,  750,  750,  750,  750,  750,
+      750,  750,  750,  750,  750,  750,  750,  750,  750,  750,
+      753,  507,  450,  500, 1819,  450, 1054, 1116, 2915,  907,
+     1270, 2915, 1387,  908,  501, 2915, 1488, 1383,  450,  450,
+     2915, 1384, 1820, 2871, 2915, 1489, 1055, 1055, 1055, 1055,
+     1055, 1055, 1056, 1056, 1056, 1057,  760,  760,  760,  760,
+      760,  760,  761,  761,  761,  762, 1143, 2869,  450,  753,
+      753,  753,  753,  753,  753,  753,  753,  753,  753,  753,
+
+      753,  753,  753,  753,  753,  753,  753,  753,  766,  766,
+      766,  766,  766,  766,  767,  767,  767,  768,  753,  753,
+      759,  772,  772,  772,  772,  772,  772,  773,  773,  773,
+      774,  780,  780,  780,  780,  780,  780,  781,  781,  781,
+      782,  788,  788,  788,  788,  788,  788,  789,  789,  789,
+      790,  796,  796,  796,  796,  796,  796,  797,  797,  797,
+      798,  450,  450, 2778, 2778, 2780, 2780, 1585, 1519,  759,
+      759,  759,  759,  759,  759,  759,  759,  759,  759,  759,
+      759,  759,  759,  759,  759,  759,  759,  759,  802,  802,
+      802,  802,  802,  802,  803,  803,  803,  804,  759,  759,
+
+      765,  808,  808,  808,  808,  808,  808,  809,  809,  809,
+      810,  818,  818,  818,  818,  818,  818,  819,  819,  819,
+      820,  824,  824,  824,  824,  824,  824,  825,  825,  825,
+      826,  830,  830,  830,  830,  830,  830,  831,  831,  831,
+      832,  450, 1600, 2867, 2866, 2865, 2861, 1560,  450,  765,
+      765,  765,  765,  765,  765,  765,  765,  765,  765,  765,
+      765,  765,  765,  765,  765,  765,  765,  765,  839,  839,
+      839,  839,  839,  839,  840,  840,  840,  841,  765,  765,
+      771,  845,  845,  845,  845,  845,  845,  846,  846,  846,
+      847,  851,  851,  851,  851,  851,  851,  852,  852,  852,
+
+      853,  857,  857,  857,  857,  857,  857,  858,  858,  858,
+      859,  450, 1390, 2857,  450, 2856,  450,  450,  450, 1113,
+      450, 1389, 1391, 1114, 1431, 1392, 1438, 1439, 1495,  771,
+      771,  771,  771,  771,  771,  771,  771,  771,  771,  771,
+      771,  771,  771,  771,  771,  771,  771,  771, 1088,  870,
+     1100, 1103, 1089,  870, 1101, 1104,  450, 1120,  771,  771,
+      779, 1121, 1115, 2847,  450, 1140, 2845, 1128, 1090, 1141,
+      453, 1129,  925, 1105,  954, 1484,  925, 1427,  954, 1102,
+     1367, 1428, 1497, 2844, 1085,  450, 1122,  450,  450, 1130,
+     1092, 1498,  450,  453,  450,  453, 1131,  450, 1142,  912,
+
+     1182, 1363,  450,  913,  450, 1562, 2843, 1526,  450,  779,
+      779,  779,  779,  779,  779,  779,  779,  779,  779,  779,
+      779,  779,  779,  779,  779,  779,  779,  779,  908,  907,
+     1146, 1149,  908,  908, 1147, 1150, 1152, 2842,  779,  779,
+      787,  913,  912, 1156,  917,  913,  913, 1157,  918,  453,
+     1178, 2841, 1113, 1151, 1179, 1148, 1114, 1154, 1145,  450,
+     1493, 1494,  453, 1504, 1505, 1144,  450,  450,  450, 2840,
+      450,  531, 1383, 1216, 1506,  450, 1384, 1217, 1153,  450,
+      450, 1176, 1553,  450,  924, 2834, 1603, 1180,  925,  787,
+      787,  787,  787,  787,  787,  787,  787,  787,  787,  787,
+
+      787,  787,  787,  787,  787,  787,  787,  787,  917,  924,
+      450, 1200,  918,  925, 2833, 1201, 1183, 1218,  787,  787,
+      795,  450, 1203,  450, 1206,  944, 1204, 1222, 1207,  945,
+     1209, 1223,  450, 1616, 1210, 1158, 1159, 1181, 1691, 1202,
+      529, 2832, 1691, 1160, 2831, 1161,  450, 1162,  450, 1163,
+     1164, 1205, 1165, 1208, 1166, 1211, 1234, 1224, 1227,  450,
+     1235,  450, 1228, 1229,  450, 2830, 2826,  450, 2825,  795,
+      795,  795,  795,  795,  795,  795,  795,  795,  795,  795,
+      795,  795,  795,  795,  795,  795,  795,  795,  918, 2806,
+     1239, 1692,  918,  450, 1239, 1693, 2804, 1236,  795,  795,
+
+      801,  930, 1212,  966,  944,  931, 1213,  966,  945,  453,
+     1114,  453, 1241, 2915, 1114, 1167, 1168, 1435, 2802, 2800,
+     2560, 1436, 1214, 1169,  453, 1170, 1186, 1171, 1187, 1172,
+     1173,  453, 1174, 1243, 1175, 2560, 1188, 1244,  450,  450,
+     1189,  450, 1190, 1191, 1192, 1251, 2799, 1233,  450,  801,
+      801,  801,  801,  801,  801,  801,  801,  801,  801,  801,
+      801,  801,  801,  801,  801,  801,  801,  801,  931, 1238,
+      450, 2131,  931, 1239, 2798, 1245, 2797, 2132,  801,  801,
+      807,  945, 2796,  953,  953,  945,  965,  954,  954,  453,
+      966, 1240, 1383, 1193, 1134, 1194, 1384, 2795, 1134, 2781,
+
+     2773, 1204,  453, 1195,  975, 1204,  450, 1196,  975, 1197,
+     1198, 1199,  965, 1258, 1230, 1136,  966, 1259, 1231, 1232,
+      450,  450,  453,  450, 1261,  978, 2772, 1246, 1250,  807,
+      807,  807,  807,  807,  807,  807,  807,  807,  807,  807,
+      807,  807,  807,  807,  807,  807,  807,  807, 1255, 1253,
+      450, 1260, 1256, 1263, 2771, 2770, 2769, 1264,  807,  807,
+      817, 1271,  988,  989, 2767, 1272,  989,  989,  991,  991,
+     1696, 2762,  992,  992, 1697, 1265, 1213, 1257, 2760, 1217,
+     1213,  450, 1266, 1217,  453,  450, 1023, 1273, 1275, 2759,
+      450,  988, 2756, 1583, 2754,  989, 1543,  453,  450,  450,
+
+      453, 1274, 1276, 1023, 1084, 1278,  450, 1280, 1085,  817,
+      817,  817,  817,  817,  817,  817,  817,  817,  817,  817,
+      817,  817,  817,  817,  817,  817,  817,  817,  450,  992,
+     2752, 2750, 1698,  992, 1277,  450, 1699,  450,  817,  817,
+      823,  451, 1101, 1368, 1121,  452, 1101, 2748, 1121, 1615,
+      453,  719,  719,  719,  719,  719,  719,  720,  720,  720,
+      721, 2746,  718,  453, 2745,  453, 1279, 1025,  719,  719,
+      719,  719,  719,  719,  720,  720,  720,  721,  718, 1399,
+     2744, 1441,  451, 1030, 1688, 2743,  452, 2742, 1042,  823,
+      823,  823,  823,  823,  823,  823,  823,  823,  823,  823,
+
+      823,  823,  823,  823,  823,  823,  823,  823,  739,  739,
+      739,  739,  739,  739,  740,  740,  740,  741,  823,  823,
+      829,  727,  728,  729,  730,  731,  732,  733,  734,  735,
+      736, 2741, 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1027,
+     1027, 1028,  718, 2740, 2739, 2722, 2714, 1035, 1031, 1031,
+     1031, 1031, 1031, 1031, 1032, 1032, 1032, 1033,  718, 2713,
+     1720,  451, 1707, 1025, 1721,  452, 1708, 2712, 1042,  829,
+      829,  829,  829,  829,  829,  829,  829,  829,  829,  829,
+      829,  829,  829,  829,  829,  829,  829,  829,  739,  739,
+      739,  739,  739,  739,  740,  740,  740,  741,  829,  829,
+
+      838, 2711, 1084, 1380, 1709, 1157, 1085, 1372, 2710, 1157,
+     2709, 2707, 1036, 1036, 1036, 1036, 1036, 1036, 1037, 1037,
+     1037, 1038,  718, 1381, 1375, 1382,  453, 1283, 1026, 1026,
+     1026, 1026, 1026, 1026, 1027, 1027, 1027, 1028,  718, 2702,
+     1687, 1100, 1449, 1288, 1393, 1101, 1450, 1486, 1394,  838,
+      838,  838,  838,  838,  838,  838,  838,  838,  838,  838,
+      838,  838,  838,  838,  838,  838,  838,  838, 2700, 1395,
+     1451, 2635,  450,  450, 2698,  450, 2697,  451,  838,  838,
+      844,  452, 1400, 1408, 1393, 1141,  451, 1104, 1394, 1141,
+      452, 2694, 1284, 1284, 1284, 1284, 1284, 1284, 1285, 1285,
+
+     1285, 1286,  718, 2692, 1404, 1409,  453, 1293, 1289, 1289,
+     1289, 1289, 1289, 1289, 1290, 1290, 1290, 1291,  718, 1700,
+      878, 1120, 1459, 1298,  879, 1121, 2688, 1712, 2684,  844,
+      844,  844,  844,  844,  844,  844,  844,  844,  844,  844,
+      844,  844,  844,  844,  844,  844,  844,  844, 2682, 1129,
+      451,  450,  450, 1129, 1724, 2681, 2680, 1397,  844,  844,
+      850,  451, 1442, 2679, 1150,  452, 1453, 1453, 1150, 2678,
+      453, 1454, 1294, 1294, 1294, 1294, 1294, 1294, 1295, 1295,
+     1295, 1296,  718, 2677, 2676, 1468, 1472, 1304, 1299, 1299,
+     1299, 1299, 1299, 1299, 1300, 1300, 1300, 1301,  718, 2675,
+
+     1100, 1455,  907, 1309, 1101, 1456,  908, 2659, 2657,  850,
+      850,  850,  850,  850,  850,  850,  850,  850,  850,  850,
+      850,  850,  850,  850,  850,  850,  850,  850, 2651, 2650,
+     1147,  450,  450,  450, 1147, 2649, 2648, 1398,  850,  850,
+      856, 1551, 1179, 1210, 1207, 1219, 1179, 1210, 1207, 2647,
+     2646,  453, 1305, 1305, 1305, 1305, 1305, 1305, 1306, 1306,
+     1306, 1307, 1552,  453,  453,  453, 2642, 1464, 1310, 1310,
+     1310, 1310, 1310, 1310, 1311, 1311, 1311, 1312,  718, 1515,
+     1120, 1538, 1713, 1314, 1121, 1541, 1714, 2640,  738,  856,
+      856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
+
+      856,  856,  856,  856,  856,  856,  856,  856, 1445, 1128,
+     1689,  450, 1446, 1129, 1690, 2638, 2636, 1440,  856,  856,
+      451, 1715, 2635, 2634,  452,  451, 1452, 1452, 1447,  452,
+     1370, 1130,  450, 1100, 2633, 2630,  738, 1101, 1044,  450,
+      450,  453, 1140, 1146, 2628, 2624, 1141, 1147, 1315, 1315,
+     1315, 1315, 1315, 1315, 1316, 1316, 1316, 1317, 1045, 1045,
+     1045, 1045, 1045, 1045, 1046, 1046, 1046, 1047,  738, 1719,
+     1694,  924, 1200,  450,  450,  925, 1201, 1726,  738, 1458,
+     1463, 1727, 2617, 1223, 1393,  912, 1049, 1223, 1394,  913,
+     2615,  454,  454,  454,  454,  454,  454,  455,  455,  455,
+
+      456,  451,  450,  450,  453,  452, 1050, 1050, 1050, 1050,
+     1050, 1050, 1051, 1051, 1051, 1052,  450, 2614, 1054,  738,
+     1557, 1710,  453, 2613, 1483,  451, 2612, 1146, 1044,  452,
+     1178, 1147, 1203,  738, 1179, 2611, 1204, 2610, 1055, 1055,
+     1055, 1055, 1055, 1055, 1056, 1056, 1056, 1057, 1045, 1045,
+     1045, 1045, 1045, 1045, 1046, 1046, 1046, 1047,  450, 2609,
+     2608,  450, 1725,  450, 1235, 2591, 2587, 1514, 1235, 1320,
+     1465, 2580,  454,  454,  454,  454,  454,  454,  455,  455,
+      455,  456, 2915, 1325, 2579,  453,  450, 2569,  450, 1321,
+     1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322, 1323, 2565,
+
+     2561, 2559,  738, 1326, 1326, 1326, 1326, 1326, 1326, 1327,
+     1327, 1327, 1328, 2558, 2555,  451, 1752, 1120,  451,  452,
+     1753, 1121,  452, 1156,  917, 1206, 1756, 1157,  918, 1207,
+     1757, 2548, 2546,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+      450,  450, 1330, 1178,  450,  450,  450, 1179, 1728, 1731,
+     1751, 2544,  450,  450,  457, 1485, 1539, 1509,  458, 2533,
+     2532, 2531, 1331, 1331, 1331, 1331, 1331, 1331, 1332, 1332,
+     1332, 1333, 1516, 1704,  450, 2530, 2529, 1705, 2528,  459,
+      460,  461,  462,  463,  464, 2527,  465,  466, 2526,  467,
+
+      468,  469,  470,  471,  472,  473,  474,  475,  476,  477,
+      478, 2503, 1706,  479,  973,  974,  973,  973,  973,  975,
+      976,  973,  976,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  977,  978,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  979,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  976,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  980,  980,  980,  980,
+      980,  980,  981,  981,  981,  982,  976,  976,  560,  561,
+
+      562,  560,  560,  561,  560,  560,  560,  560,  560,  560,
+      563,  560,  560,  560,  560,  560,  560,  560,  564,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  562,  562,  562,  562,  562,  562,  562,  562,  562,
+      562,  562,  562,  562,  562,  562,  562,  562,  562,  562,
+      565,  565,  565,  565,  565,  565,  566,  566,  566,  567,
+      562,  562,  563, 1510, 1520, 1206, 1212, 1511, 1521, 1207,
+     1213, 1239, 1765, 2502, 2499, 1239, 1766, 1256,  452, 2498,
+
+     2489, 1256, 1262, 1512, 1522, 1767, 1214, 1455, 2488, 1767,
+     2487, 1456,  453, 1241,  450,  450,  450,  450,  453,  453,
+     2485, 1513, 1537,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  568,  568,  568,  568,  568,  568,  568,  568,
+      568,  568,  568,  568,  568,  568,  568,  568,  568,  568,
+      568,  569,  569,  569,  569,  569,  569,  569,  569,  569,
+      569,  569,  569,  569,  569,  569,  569,  569,  569,  569,
+      999,  999,  999,  999,  999,  999,  999,  999,  999,  999,
+      999,  999,  999,  999,  999,  999,  999,  999,  999,  570,
+
+     1128, 1200, 1544, 1209, 1129, 1201, 1545, 1210, 1216, 1445,
+     2484, 2480, 1217, 1446, 1367, 1554, 1613,  738, 1085, 1555,
+     1606, 1792, 1130,  451, 2479, 1793, 1186,  452, 1187, 1447,
+      738,  450,  450,  450,  450, 1363, 1188, 1608, 1614,  450,
+     1189, 1457, 1190, 1191, 1192, 1540,  450,  738,  570,  570,
+      570,  570,  570,  570,  570,  570,  570,  570,  570,  570,
+      570,  570,  570,  570,  570,  570,  570, 1335, 1203, 1768,
+      451, 1701, 1204, 1769,  452, 1702, 2476,  570,  570,  576,
+     1341, 1222, 1546, 2469, 1770, 1223, 1547, 1336, 1336, 1336,
+     1336, 1336, 1336, 1337, 1337, 1337, 1338, 1346, 1703,  450,
+
+     1342, 1342, 1342, 1342, 1342, 1342, 1343, 1343, 1343, 1344,
+     1548, 1558,  450,  450, 2468, 1536, 1805, 1347, 1347, 1347,
+     1347, 1347, 1347, 1348, 1348, 1348, 1349, 1042,  576,  576,
+      576,  576,  576,  576,  576,  576,  576,  576,  576,  576,
+      576,  576,  576,  576,  576,  576,  576,  739,  739,  739,
+      739,  739,  739,  740,  740,  740,  741,  576,  576,  582,
+      582,  583,  582,  583,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  584,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  583,  583,  583,  583,  583,  583,  583,  583,
+      583,  583,  583,  583,  583,  583,  583,  583,  583,  583,
+      583,  585,  585,  585,  585,  585,  585,  586,  586,  586,
+      587,  583,  583,  582, 1201, 1209,  944, 1222, 1201, 1210,
+      945, 1223, 1259,  451, 1384, 2467, 1259,  452, 1384, 1234,
+     1238, 2466,  588, 1235, 1239,  453,  917, 2463, 1825, 1193,
+      918, 1194, 1826,  453,  738,  453,  450,  450,  450, 1195,
+     1729, 2456, 1240, 1196, 1556, 1197, 1198, 1199, 1542, 1589,
+      450,  450,  582,  582,  582,  582,  582,  582,  582,  582,
+
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  588, 1351, 1568, 1243, 1234, 1578, 1569,
+     1244, 1235, 1579,  953,  965, 1580,  912,  954,  966, 1581,
+      913, 2453, 2451, 2447, 1352, 1352, 1352, 1352, 1352, 1352,
+     1353, 1353, 1353, 1354, 1566, 1582,  450,  450,  450,  450,
+     2443, 2438, 1577, 1243,  450,  450,  450, 1244, 2437, 1576,
+     2436, 1797,  588,  588,  588,  588,  588,  588,  588,  588,
+      588,  588,  588,  588,  588,  588,  588,  588,  588,  588,
+      588, 1572, 1244, 1255,  450, 1255, 1244, 1256, 2435, 1256,
+
+     1258,  588,  588,  596, 1259, 1573, 2434, 1258, 2433, 2432,
+     1263, 1259, 1595,  453, 1264, 1598, 1596, 1601, 1264, 1599,
+     1574, 1602, 1264, 2431,  450, 1587,  450, 1592, 1592, 1774,
+     2430,  450, 1265, 1775, 1575, 1593, 1593, 1588,  450,  453,
+     1594,  450, 2414,  450, 1590,  988,  450,  451,  450,  989,
+     1023,  452,  596,  596,  596,  596,  596,  596,  596,  596,
+      596,  596,  596,  596,  596,  596,  596,  596,  596,  596,
+      596, 1263, 1776,  991, 1619, 1264,  450,  992, 2412, 2406,
+     1773,  596,  596,  602, 2405,  878, 1023, 1380, 1622,  879,
+     2402, 1372, 1394, 1265,  718, 2400, 1394,  451, 2398, 1025,
+
+     2386,  452,  450, 2385,  450,  718, 2384, 1381, 1375, 1382,
+     1030, 2380, 1597,  453, 1716,  719,  719,  719,  719,  719,
+      719,  720,  720,  720,  721,  718, 1717, 1178, 2379, 1711,
+     1035, 1179,  602,  602,  602,  602,  602,  602,  602,  602,
+      602,  602,  602,  602,  602,  602,  602,  602,  602,  602,
+      602,  719,  719,  719,  719,  719,  719,  720,  720,  720,
+      721,  602,  602,  608, 1026, 1026, 1026, 1026, 1026, 1026,
+     1027, 1027, 1027, 1028, 2374, 1031, 1031, 1031, 1031, 1031,
+     1031, 1032, 1032, 1032, 1033,  718, 2370, 1380, 1834, 1203,
+     1025, 1372, 1835, 1204, 2369, 1036, 1036, 1036, 1036, 1036,
+
+     1036, 1037, 1037, 1037, 1038,  718, 2366, 1381, 1375, 1382,
+     1025, 1042,  608,  608,  608,  608,  608,  608,  608,  608,
+      608,  608,  608,  608,  608,  608,  608,  608,  608,  608,
+      608,  739,  739,  739,  739,  739,  739,  740,  740,  740,
+      741,  608,  608,  614, 2364, 1408, 2361, 1722,  452, 1104,
+      451, 1412,  452, 2359,  452, 1026, 1026, 1026, 1026, 1026,
+     1026, 1027, 1027, 1027, 1028,  718, 1404, 1409, 1414,  453,
+     1283, 2358, 2352, 2347, 2344, 1026, 1026, 1026, 1026, 1026,
+     1026, 1027, 1027, 1027, 1028,  718, 1730,  451, 2342, 2340,
+     1288,  452,  614,  614,  614,  614,  614,  614,  614,  614,
+
+      614,  614,  614,  614,  614,  614,  614,  614,  614,  614,
+      614, 1420,  451, 1446, 1853, 1420,  452, 1446, 1853, 2335,
+     1745,  614,  614,  620, 1746, 2333,  451, 2331, 2328, 1744,
+      452, 1723, 1423, 1755,  453, 1284, 1284, 1284, 1284, 1284,
+     1284, 1285, 1285, 1285, 1286,  718, 2327, 1544, 1456, 1747,
+     1293, 1545, 1456, 1758, 1748, 1289, 1289, 1289, 1289, 1289,
+     1289, 1290, 1290, 1290, 1291,  718, 2324,  451, 1758,  453,
+     1298,  452,  620,  620,  620,  620,  620,  620,  620,  620,
+      620,  620,  620,  620,  620,  620,  620,  620,  620,  620,
+      620,  451, 2319, 1794,  451,  452, 1749, 1475,  452, 2313,
+
+      451,  620,  620,  626,  452, 1759, 1760, 2311, 2310, 1760,
+     1760, 1452, 1452, 2309, 1477, 1294, 1294, 1294, 1294, 1294,
+     1294, 1295, 1295, 1295, 1296,  718, 2308,  453, 2307, 1771,
+     1298, 2306, 1754, 1761, 1763, 1299, 1299, 1299, 1299, 1299,
+     1299, 1300, 1300, 1300, 1301,  718, 2305, 1762, 1764, 2304,
+     1304, 2303,  626,  626,  626,  626,  626,  626,  626,  626,
+      626,  626,  626,  626,  626,  626,  626,  626,  626,  626,
+      626, 1777, 1782,  451,  451, 1777, 1783,  452,  452, 2280,
+      451,  626,  626,  632,  452, 1785, 1785,  451,  451, 1785,
+     1785,  452,  452, 2279, 1784, 1299, 1299, 1299, 1299, 1299,
+
+     1299, 1300, 1300, 1300, 1301,  718, 2276, 1786, 1786, 1779,
+     1309, 1807, 1803, 1809, 1778, 1305, 1305, 1305, 1305, 1305,
+     1305, 1306, 1306, 1306, 1307,  718, 1838, 1146, 2915, 2915,
+     1314, 1147,  632,  632,  632,  632,  632,  632,  632,  632,
+      632,  632,  632,  632,  632,  632,  632,  632,  632,  632,
+      632, 1787, 2264, 1858, 1510, 1787, 1781, 1859, 1511, 2263,
+     2260,  632,  632,  638, 1788, 1790,  451, 1798, 1788, 1790,
+      452, 1799, 2257, 1784, 1512, 1310, 1310, 1310, 1310, 1310,
+     1310, 1311, 1311, 1311, 1312,  718, 1789, 1791,  451, 1800,
+     1025, 2252,  452, 2238, 2236, 1315, 1315, 1315, 1315, 1315,
+
+     1315, 1316, 1316, 1316, 1317,  718, 2235,  451, 2234, 1795,
+     1283,  452,  638,  638,  638,  638,  638,  638,  638,  638,
+      638,  638,  638,  638,  638,  638,  638,  638,  638,  638,
+      638, 1801,  451, 2233, 1520,  451,  452, 1804, 1521,  452,
+     2232,  638,  638,  644,  451,  451, 1511,  451,  452,  452,
+     1511,  452, 2229, 2228, 1522, 1026, 1026, 1026, 1026, 1026,
+     1026, 1027, 1027, 1027, 1028,  718, 1824,  453, 1806,  451,
+     1288, 1832, 1837,  452, 2222, 1284, 1284, 1284, 1284, 1284,
+     1284, 1285, 1285, 1285, 1286,  718, 2214,  882,  911, 2213,
+     1293, 2208,  644,  644,  644,  644,  644,  644,  644,  644,
+
+      644,  644,  644,  644,  644,  644,  644,  644,  644,  644,
+      644, 1521, 1836, 1545, 1877, 1521, 2205, 1545, 1878, 2203,
+      451,  644,  644,  650,  452,  451, 1206, 2202, 1976,  452,
+     1207, 1833,  453, 2191,  453, 1289, 1289, 1289, 1289, 1289,
+     1289, 1290, 1290, 1290, 1291,  718, 2188, 2186,  451,  451,
+     1025, 1808,  452,  452, 1828, 1294, 1294, 1294, 1294, 1294,
+     1294, 1295, 1295, 1295, 1296,  718, 2183,  451, 1849,  943,
+     1025,  452,  650,  650,  650,  650,  650,  650,  650,  650,
+      650,  650,  650,  650,  650,  650,  650,  650,  650,  650,
+      650, 2181, 1850, 2170,  451,  901, 1203, 1830,  452, 2168,
+
+     1204,  650,  650,  656,  451,  451, 2166, 1551,  452,  452,
+      451, 1862, 2163, 2162,  452, 1026, 1026, 1026, 1026, 1026,
+     1026, 1027, 1027, 1027, 1028,  718, 2161,  933, 1552,  451,
+     1283, 1860, 2156,  452, 1847, 1026, 1026, 1026, 1026, 1026,
+     1026, 1027, 1027, 1027, 1028,  718, 2146, 2142, 2138, 1879,
+     1288,  957,  656,  656,  656,  656,  656,  656,  656,  656,
+      656,  656,  656,  656,  656,  656,  656,  656,  656,  656,
+      656, 2133, 1880, 1568, 1570, 1843, 2130, 1569, 1570, 1843,
+     1209,  656,  656,  664, 1210, 1546, 1547, 1909,  451, 1547,
+     1547, 1910,  452, 2129, 2128, 1284, 1284, 1284, 1284, 1284,
+
+     1284, 1285, 1285, 1285, 1286,  718, 1844,  453, 1872, 1852,
+     1293, 2127, 1555, 1854, 1856, 1289, 1289, 1289, 1289, 1289,
+     1289, 1290, 1290, 1290, 1291,  718, 2116, 1855, 1857, 1867,
+     1283, 1881,  664,  664,  664,  664,  664,  664,  664,  664,
+      664,  664,  664,  664,  664,  664,  664,  664,  664,  664,
+      664, 1222, 1569, 1873, 1243, 1223, 1569, 2115, 1244, 2110,
+      451,  664,  664,  670,  452,  451, 2109,  451, 1580,  452,
+      953,  452, 1581,  453,  954, 1294, 1294, 1294, 1294, 1294,
+     1294, 1295, 1295, 1295, 1296,  718, 1876, 1892, 1582, 1863,
+     1624, 2103, 1911, 1861, 1874, 1284, 1284, 1284, 1284, 1284,
+
+     1284, 1285, 1285, 1285, 1286,  718, 1893, 1234, 2087, 2086,
+     1629, 1235,  670,  670,  670,  670,  670,  670,  670,  670,
+      670,  670,  670,  670,  670,  670,  670,  670,  670,  670,
+      670,  451, 2083, 1581,  451,  452, 1885, 1581,  452, 2080,
+      451,  670,  670,  676,  452,  451, 1887, 1258, 1917,  452,
+     2078, 1259, 1917, 1908,  453, 1625, 1625, 1625, 1625, 1625,
+     1625, 1626, 1626, 1626, 1627,  718, 2077,  451, 1886, 1595,
+     1634,  452, 2075, 1596, 1888, 1630, 1630, 1630, 1630, 1630,
+     1630, 1631, 1631, 1631, 1632,  718, 2074,  451, 2073, 2059,
+     1304,  452,  676,  676,  676,  676,  676,  676,  676,  676,
+
+      676,  676,  676,  676,  676,  676,  676,  676,  676,  676,
+      676, 2054, 2051, 1255,  451, 1889, 1915, 1256,  452, 2050,
+      451,  676,  676,  682,  452, 2049, 1596, 2048, 2047, 1598,
+     1596, 1592, 1592, 1599, 2046, 1635, 1635, 1635, 1635, 1635,
+     1635, 1636, 1636, 1636, 1637,  718, 1914,  453, 1913, 1924,
+     1639, 2044, 2040, 1925, 2039, 1305, 1305, 1305, 1305, 1305,
+     1305, 1306, 1306, 1306, 1307,  718, 1921,  451, 2032, 1370,
+     1644,  452,  682,  682,  682,  682,  682,  682,  682,  682,
+      682,  682,  682,  682,  682,  682,  682,  682,  682,  682,
+      682, 1918, 1599,  451,  988, 1919, 1599,  452,  989, 2009,
+
+     2006,  682,  682,  689, 1923, 1926, 1920,  451,  451, 1925,
+     1927,  452,  452,  453, 1928, 1640, 1640, 1640, 1640, 1640,
+     1640, 1641, 1641, 1641, 1642,  718, 1375, 1382, 2000, 1922,
+     1649, 1999, 1929, 1990, 1984, 1645, 1645, 1645, 1645, 1645,
+     1645, 1646, 1646, 1646, 1647,  451, 1934, 1691, 1983,  452,
+     1269, 1691,  689,  689,  689,  689,  689,  689,  689,  689,
+      689,  689,  689,  689,  689,  689,  689,  689,  689,  689,
+      689, 1741, 1613,  991, 1692, 1436, 1606,  992, 1693, 1976,
+     1692,  689,  689,  695, 1693, 1720, 1930, 1510, 1937, 1721,
+     1931, 1511, 1735, 1608, 1614, 1650, 1650, 1650, 1650, 1650,
+
+     1650, 1651, 1651, 1651, 1652,  738, 1742, 1512,  450, 1613,
+     1720, 1974, 1939, 1606, 1721,  738, 1995, 1743, 1827, 1767,
+     1995, 1777, 1777, 1767, 2018, 1777, 1777, 1967, 2019, 1951,
+     1608, 1614,  695,  695,  695,  695,  695,  695,  695,  695,
+      695,  695,  695,  695,  695,  695,  695,  695,  695,  695,
+      695, 1938, 1932, 1792, 1792, 1044, 1933, 1793, 1793, 1936,
+     2055,  695,  695,  701, 2055, 1049, 1023, 1578, 2063, 2066,
+     1935, 1579, 2063, 2066, 2915, 1045, 1045, 1045, 1045, 1045,
+     1045, 1046, 1046, 1046, 1047, 1050, 1050, 1050, 1050, 1050,
+     1050, 1051, 1051, 1051, 1052,  738, 1894, 1895, 1591, 1843,
+
+     1896, 2064, 1897, 1843, 1898,  738, 1853, 1916, 1912, 1899,
+     1853, 1900,  701,  701,  701,  701,  701,  701,  701,  701,
+      701,  701,  701,  701,  701,  701,  701,  701,  701,  701,
+      701,  719,  719,  719,  719,  719,  719,  720,  720,  720,
+      721,  701,  701,  707, 2071, 1054, 2136, 1917, 2071, 1932,
+     2136, 1917, 1891, 1933, 1932, 1044, 1843, 1890, 1933, 2155,
+     1843,  738, 1884, 2155, 2072, 1055, 1055, 1055, 1055, 1055,
+     1055, 1056, 1056, 1056, 1057, 1045, 1045, 1045, 1045, 1045,
+     1045, 1046, 1046, 1046, 1047, 2076, 1995, 2100, 1883, 1882,
+     1995, 2100,  707,  707,  707,  707,  707,  707,  707,  707,
+
+      707,  707,  707,  707,  707,  707,  707,  707,  707,  707,
+      707, 1044, 2101, 2018, 1084, 2018, 2220, 2019, 1085, 2019,
+     2220,  707,  707,  744, 1949, 1722, 1705, 1875, 1690, 1412,
+     1705, 1045, 1045, 1045, 1045, 1045, 1045, 1046, 1046, 1046,
+     1047,  738,  450, 1861, 2055, 1375, 1414,  453, 2055, 2063,
+      450,  738, 1861, 2063, 1851, 2063, 1947, 1848,  450, 2063,
+      745,  746,  746, 1961,  747,  748,  749,  750,  750,  750,
+      750,  750,  750,  750,  750,  750,  750,  750,  750,  750,
+      750,  750,  750,  750,  750,  750,  750,  750,  753, 1697,
+     2066, 1320, 2245, 1697, 2066, 1691, 2267, 1846, 2273, 1691,
+
+     2267, 1325, 2100, 2136, 2320, 2220,  738, 2136, 2320, 2220,
+      453, 1321, 1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322,
+     1323, 1326, 1326, 1326, 1326, 1326, 1326, 1327, 1327, 1327,
+     1328, 1953, 1845, 1842, 1841, 1840,  738,  753,  753,  753,
+      753,  753,  753,  753,  753,  753,  753,  753,  753,  753,
+      753,  753,  753,  753,  753,  753, 1330, 1843, 2270, 2100,
+     2381, 1843, 2098, 2100, 2381, 1839,  753,  753,  759, 1042,
+     2055, 1831, 1829, 1823, 2055, 2382, 1331, 1331, 1331, 1331,
+     1331, 1331, 1332, 1332, 1332, 1333, 1335,  738, 1822,  739,
+      739,  739,  739,  739,  739,  740,  740,  740,  741,  738,
+
+     2274, 1843, 1821, 1864, 2256, 1843, 1336, 1336, 1336, 1336,
+     1336, 1336, 1337, 1337, 1337, 1338, 1023,  759,  759,  759,
+      759,  759,  759,  759,  759,  759,  759,  759,  759,  759,
+      759,  759,  759,  759,  759,  759, 2071, 1335, 2387, 2063,
+     2071, 2267, 2387, 2063, 1818, 2267,  759,  759,  765, 1341,
+     2270, 2273, 1817, 2388, 2098, 2100, 2072, 1336, 1336, 1336,
+     1336, 1336, 1336, 1337, 1337, 1337, 1338,  738, 2391, 1342,
+     1342, 1342, 1342, 1342, 1342, 1343, 1343, 1343, 1344,  738,
+     1816,  719,  719,  719,  719,  719,  719,  720,  720,  720,
+      721,  718, 1815, 1814, 1813, 1864, 1025,  765,  765,  765,
+
+      765,  765,  765,  765,  765,  765,  765,  765,  765,  765,
+      765,  765,  765,  765,  765,  765, 2253, 1346, 2289, 2291,
+     2253, 2320, 2289, 2291, 1812, 2320,  765,  765,  771, 1351,
+     2448, 2454, 1811, 1810, 2448, 2454, 1755, 1347, 1347, 1347,
+     1347, 1347, 1347, 1348, 1348, 1348, 1349,  738, 1802, 1352,
+     1352, 1352, 1352, 1352, 1352, 1353, 1353, 1353, 1354,  738,
+     1796, 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1027, 1027,
+     1028,  718, 1780, 1772, 1750, 1718, 1030,  771,  771,  771,
+      771,  771,  771,  771,  771,  771,  771,  771,  771,  771,
+      771,  771,  771,  771,  771,  771, 2258, 1044, 2474, 2510,
+
+     2258, 2538, 2474, 2510, 1695, 2538,  771,  771,  779, 1320,
+     2448, 2289, 1683, 2915, 2448, 2289, 1908, 1045, 1045, 1045,
+     1045, 1045, 1045, 1046, 1046, 1046, 1047,  738, 2915, 1321,
+     1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322, 1323,  738,
+     2515, 1031, 1031, 1031, 1031, 1031, 1031, 1032, 1032, 1032,
+     1033,  718, 2915, 2915, 2915, 2915, 1035,  779,  779,  779,
+      779,  779,  779,  779,  779,  779,  779,  779,  779,  779,
+      779,  779,  779,  779,  779,  779, 2329, 1325, 2454, 2474,
+     2329, 2570, 2454, 2474, 2915, 2570,  779,  779,  787, 1330,
+     2063, 2510, 2915, 1621, 2063, 2510, 1261, 1326, 1326, 1326,
+
+     1326, 1326, 1326, 1327, 1327, 1327, 1328,  738, 1618, 1331,
+     1331, 1331, 1331, 1331, 1331, 1332, 1332, 1332, 1333,  738,
+     1617, 1036, 1036, 1036, 1036, 1036, 1036, 1037, 1037, 1037,
+     1038,  718, 1591, 1584,  450, 1565, 1025,  787,  787,  787,
+      787,  787,  787,  787,  787,  787,  787,  787,  787,  787,
+      787,  787,  787,  787,  787,  787, 2337, 1044, 2291, 2570,
+     2338, 2575, 2291, 2570, 1564, 2576,  787,  787,  795, 1044,
+     2577, 2289, 2578, 1563,  450, 2289, 2171, 1045, 1045, 1045,
+     1045, 1045, 1045, 1046, 1046, 1046, 1047,  738, 1535, 1045,
+     1045, 1045, 1045, 1045, 1045, 1046, 1046, 1046, 1047,  738,
+
+     1534, 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1027, 1027,
+     1028,  718, 1533, 1532, 1531, 1530, 1025,  795,  795,  795,
+      795,  795,  795,  795,  795,  795,  795,  795,  795,  795,
+      795,  795,  795,  795,  795,  795, 2253, 1320, 2705, 2725,
+     2253, 2765, 2705, 2725, 1529, 2765,  795,  795,  801, 1325,
+     2100, 2100, 1518, 1508, 2100, 2100, 1755, 1321, 1321, 1321,
+     1321, 1321, 1321, 1322, 1322, 1322, 1323,  738, 1507, 1326,
+     1326, 1326, 1326, 1326, 1326, 1327, 1327, 1327, 1328,  738,
+     2729, 1026, 1026, 1026, 1026, 1026, 1026, 1027, 1027, 1027,
+     1028,  718, 2787, 1503, 1502, 1499, 1283,  801,  801,  801,
+
+      801,  801,  801,  801,  801,  801,  801,  801,  801,  801,
+      801,  801,  801,  801,  801,  801, 2254, 1330, 2788, 2829,
+     2254, 2765, 2788, 2829, 1496, 2765,  801,  801,  807, 1320,
+     2810, 2788, 1482, 1462, 2810, 2788, 1824, 1331, 1331, 1331,
+     1331, 1331, 1331, 1332, 1332, 1332, 1333,  738,  450, 1321,
+     1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322, 1323,  738,
+      450, 1284, 1284, 1284, 1284, 1284, 1284, 1285, 1285, 1285,
+     1286,  718, 2811, 1386, 1355, 2915, 1288,  807,  807,  807,
+      807,  807,  807,  807,  807,  807,  807,  807,  807,  807,
+      807,  807,  807,  807,  807,  807, 2258, 1654, 2850, 2810,
+
+     2258, 2853, 2850, 2810, 2915, 2853,  807,  807,  817, 1659,
+     2829, 2858,  450,  450, 2829, 2858, 1908, 1655, 1655, 1655,
+     1655, 1655, 1655, 1656, 1656, 1656, 1657,  738,  450, 1660,
+     1660, 1660, 1660, 1660, 1660, 1661, 1661, 1661, 1662,  738,
+      450, 1289, 1289, 1289, 1289, 1289, 1289, 1290, 1290, 1290,
+     1291,  718,  450,  450,  450,  450, 1293,  817,  817,  817,
+      817,  817,  817,  817,  817,  817,  817,  817,  817,  817,
+      817,  817,  817,  817,  817,  817, 2329, 1664, 2859, 2860,
+     2329, 2850, 2859, 2860,  450, 2850,  817,  817,  823, 1341,
+     2853, 2882,  450, 1112, 2853, 2882, 1261, 1665, 1665, 1665,
+
+     1665, 1665, 1665, 1666, 1666, 1666, 1667,  738,  450, 1342,
+     1342, 1342, 1342, 1342, 1342, 1343, 1343, 1343, 1344,  738,
+     1106, 1294, 1294, 1294, 1294, 1294, 1294, 1295, 1295, 1295,
+     1296,  718,  450,  816, 1068, 1066, 1298,  823,  823,  823,
+      823,  823,  823,  823,  823,  823,  823,  823,  823,  823,
+      823,  823,  823,  823,  823,  823, 2337, 1669, 2882, 2900,
+     2338, 2291, 2882, 2900, 1041, 2291,  823,  823,  829, 1674,
+     2900,  563,  563,  987, 2900,  986, 2171, 1670, 1670, 1670,
+     1670, 1670, 1670, 1671, 1671, 1671, 1672,  738,  983, 1675,
+     1675, 1675, 1675, 1675, 1675, 1676, 1676, 1676, 1677, 2420,
+
+      970, 1299, 1299, 1299, 1299, 1299, 1299, 1300, 1300, 1300,
+     1301, 2289, 2291,  964,  961, 2289, 2291,  829,  829,  829,
+      829,  829,  829,  829,  829,  829,  829,  829,  829,  829,
+      829,  829,  829,  829,  829,  829, 2100, 1679, 2292, 2289,
+     2100,  960,  952, 2289, 2290,  951,  829,  829,  838, 1579,
+     1699, 2100, 1702, 1579, 1699, 2100, 1702, 1680, 1680, 1680,
+     1680, 1680, 1680, 1681, 1681, 1681, 1682,  718,  948, 2410,
+      453,  453, 1298,  453,  937,  936, 2419, 2596, 1901, 1902,
+      718,  935, 1903,  927, 1904, 1304, 1905,  916,  915,  906,
+      718, 1906, 1955, 1907, 1958, 1309, 1042,  838,  838,  838,
+
+      838,  838,  838,  838,  838,  838,  838,  838,  838,  838,
+      838,  838,  838,  838,  838,  838,  739,  739,  739,  739,
+      739,  739,  740,  740,  740,  741,  838,  838,  844, 2254,
+     2381,  905,  902, 2254, 2381,  899,  896, 1299, 1299, 1299,
+     1299, 1299, 1299, 1300, 1300, 1300, 1301, 1453, 1453, 1824,
+     1305, 1305, 1305, 1305, 1305, 1305, 1306, 1306, 1306, 1307,
+     1310, 1310, 1310, 1310, 1310, 1310, 1311, 1311, 1311, 1312,
+      718,  895,  894,  507,  892, 1314,  886,  844,  844,  844,
+      844,  844,  844,  844,  844,  844,  844,  844,  844,  844,
+      844,  844,  844,  844,  844,  844, 1708,  452,  885, 1714,
+
+     1708, 1724,  884, 1714,  877, 1727,  844,  844,  850, 1727,
+     1757, 1760, 2100,  874, 1757, 1760, 2100,  453,  453,  718,
+      453, 2291,  871, 2063, 1025, 2291,  453, 2063,  868,  718,
+      867,  453,  453, 1964, 1025,  864, 1970, 2507,  549, 1763,
+     1315, 1315, 1315, 1315, 1315, 1315, 1316, 1316, 1316, 1317,
+      718, 2492,  544, 1764,  519, 1283, 2516,  850,  850,  850,
+      850,  850,  850,  850,  850,  850,  850,  850,  850,  850,
+      850,  850,  850,  850,  850,  850,  513,  498,  487,  816,
+      794,  786,  737,  563,  563,  556,  850,  850,  856, 1026,
+     1026, 1026, 1026, 1026, 1026, 1027, 1027, 1027, 1028, 1026,
+
+     1026, 1026, 1026, 1026, 1026, 1027, 1027, 1027, 1028,  718,
+      549, 2002, 1775, 1769, 1288, 2002, 1775, 1769,  544,  519,
+     1284, 1284, 1284, 1284, 1284, 1284, 1285, 1285, 1285, 1286,
+     1453, 1453,  453,  453,  453,  513,  498,  856,  856,  856,
+      856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
+      856,  856,  856,  856,  856,  856,  718,  487, 2100, 2387,
+     2915, 1293, 2100, 2387, 2915, 2915,  856,  856,  451, 1696,
+     2915, 1746,  452, 1697,  451, 1746, 1593, 1593,  452, 1289,
+     1289, 1289, 1289, 1289, 1289, 1290, 1290, 1290, 1291,  453,
+      718, 2915,  453, 2663, 1783, 1283, 2915,  450, 1783, 1753,
+
+     1794,  718,  450, 1753, 1475,  450, 1283, 1081, 1987, 2915,
+      450, 1952, 1950,  450, 2915,  453, 1786,  718,  450, 2915,
+      453, 1477, 1624, 2915, 2915, 2915, 1294, 1294, 1294, 1294,
+     1294, 1294, 1295, 1295, 1295, 1296, 1992, 2915, 2915,  454,
+      454,  454,  454,  454,  454,  455,  455,  455,  456,  451,
+     2915, 2915, 2915,  452, 2289, 2915, 2915, 2915, 2289, 2915,
+     1284, 1284, 1284, 1284, 1284, 1284, 1285, 1285, 1285, 1286,
+      453, 1284, 1284, 1284, 1284, 1284, 1284, 1285, 1285, 1285,
+     1286, 1785, 2599, 2915, 2915, 1785,  928, 1625, 1625, 1625,
+     1625, 1625, 1625, 1626, 1626, 1626, 1627, 1787, 2541, 2915,
+
+     2915, 1787, 2541, 1786, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 1723, 1784,
+      454,  454,  454,  454,  454,  454,  455,  455,  455,  456,
+     1132, 1133, 1132, 1132, 1132, 1134, 1135, 1132, 1135, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1136, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1135, 1135, 1135, 1135, 1135, 1135, 1135,
+     1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135,
+
+     1135, 1135, 1137, 1137, 1137, 1137, 1137, 1137, 1138, 1138,
+     1138, 1139, 1135, 1135,  973,  974,  973,  973,  973,  975,
+      976,  973,  976,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  977,  978,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  976,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  980,  980,  980,  980,
+      980,  980,  981,  981,  981,  982,  976,  976, 2915, 1686,
+
+     2915,  451,  450, 1686,  450,  452, 2022, 2915, 2025, 2013,
+     2022,  718, 2026, 1826, 2915, 2858, 1629, 1826, 1799, 2858,
+      453,  718, 1799, 2915, 2915, 2915, 1634, 1944, 2023,  450,
+      994,  718, 2776, 2776,  453, 1945, 1304,  450, 2915,  453,
+     2028,  718, 2915, 1946, 2915,  450, 1304, 2915, 1956,  450,
+      450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,  450,  450,
+      563, 1630, 1630, 1630, 1630, 1630, 1630, 1631, 1631, 1631,
+     1632, 1635, 1635, 1635, 1635, 1635, 1635, 1636, 1636, 1636,
+
+     1637, 1305, 1305, 1305, 1305, 1305, 1305, 1306, 1306, 1306,
+     1307, 1305, 1305, 1305, 1305, 1305, 1305, 1306, 1306, 1306,
+     1307,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      451,  451, 1698, 2041,  452,  452, 1699, 2041, 2915, 2045,
+     2042, 2052, 2915, 2045, 2042, 2052, 1948,  718, 2915, 1701,
+     2915,  453, 1639, 1702, 1701, 1409, 2915, 2915, 1702,  450,
+      450, 1472, 1454, 1594, 2915, 2915, 2915,  450,  450, 2043,
+     2053, 2915, 2915,  718, 1954,  450,  450,  450, 1644, 2915,
+     2586, 2915,  450,  718, 2586,  450, 2915, 2915, 1649, 2915,
+
+      450, 1957, 1741,  450, 2915, 1835, 1436, 1959,  450, 1835,
+     2336,  454,  454,  454,  454,  454,  454,  455,  455,  455,
+      456,  451, 2915, 1735, 2915,  452,  453, 1640, 1640, 1640,
+     1640, 1640, 1640, 1641, 1641, 1641, 1642, 1742, 2915, 2915,
+     2915, 2915,  453, 2915, 2915, 1704, 2915, 1704, 1743, 1705,
+     2915, 1705, 1358, 1645, 1645, 1645, 1645, 1645, 1645, 1646,
+     1646, 1646, 1647, 1650, 1650, 1650, 1650, 1650, 1650, 1651,
+     1651, 1651, 1652,  450, 2915,  450, 2915, 2915, 2915, 2915,
+     2915,  450, 1960,  450, 2915, 2915, 2915, 2915, 2915,  450,
+     1962,  450,  454,  454,  454,  454,  454,  454,  455,  455,
+
+      455,  456, 1360, 1361, 1360, 1360, 1360, 1085, 1362, 1360,
+     1362, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1363, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1362, 1362, 1362, 1362, 1362,
+     1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362,
+     1362, 1362, 1362, 1362, 1364, 1364, 1364, 1364, 1364, 1364,
+     1365, 1365, 1365, 1366, 1362, 1362, 1370, 1371, 1370, 1370,
+     1370, 1372, 1373, 1370, 1373, 1370, 1370, 1370, 1370, 1370,
+
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1374, 1375, 1376,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1373,
+     1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1377, 1377,
+     1377, 1377, 1377, 1377, 1378, 1378, 1378, 1379, 1373, 1373,
+     1401, 1402, 1401, 1401, 1401, 1104, 1403, 1401, 1403, 1401,
+     1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+     1401, 1401, 1404, 1105, 1401, 1401, 1401, 1401, 1401, 1401,
+
+     1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+     1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+     1401, 1401, 1401, 1403, 1403, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1405, 1405, 1405, 1405, 1405, 1405, 1406, 1406,
+     1406, 1407, 1403, 1403, 1410, 1411, 1410, 1410, 1410, 1412,
+     1413, 1410, 1413, 1410, 1410, 1410, 1410, 1410, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1414,  450, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410,
+
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1413, 1413, 1413,
+     1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413,
+     1413, 1413, 1413, 1413, 1413, 1413, 1415, 1415, 1415, 1415,
+     1415, 1415, 1416, 1416, 1416, 1417, 1413, 1413, 1418, 1419,
+     1418, 1418, 1418, 1420, 1421, 1418, 1421, 1418, 1418, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1422,
+     1423, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421,
+
+     1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421,
+     1424, 1424, 1424, 1424, 1424, 1424, 1425, 1425, 1425, 1426,
+     1421, 1421, 2915, 1707, 2915, 1707,  450, 1708,  450, 1708,
+     2915, 2094, 2915, 2915, 2089, 1862, 1910, 2153, 2089, 2915,
+     1910, 1931, 1924, 2915, 1949, 1919, 1925, 2915, 1690, 1919,
+     2915,  450, 2095,  450, 1965,  453, 2091,  453, 1608,  450,
+     1963,  450, 1593, 1593, 1376, 1375,  453,  450, 2915,  450,
+     2915, 2915, 2915,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450, 1437,  450,
+      450,  450, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915,  450,  450, 1132, 1133, 1132, 1132, 1132, 1134,
+     1135, 1132, 1135, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1136, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132, 1132,
+     1132, 1132, 1132, 1132, 1132, 1132, 1132, 1135, 1135, 1135,
+     1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135,
+     1135, 1135, 1135, 1135, 1135, 1135, 1137, 1137, 1137, 1137,
+     1137, 1137, 1138, 1138, 1138, 1139, 1135, 1135, 1466, 1149,
+     1466, 1466, 1466, 1150, 1467, 1466, 1467, 1466, 1466, 1466,
+
+     1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466,
+     1468, 1151, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466,
+     1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466,
+     1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466,
+     1466, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
+     1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
+     1469, 1469, 1469, 1469, 1469, 1469, 1470, 1470, 1470, 1471,
+     1467, 1467, 1473, 1474, 1473, 1473, 1473, 1475, 1476, 1473,
+     1476, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1473, 1473, 1473, 1477,  450, 1473, 1473, 1473, 1473,
+
+     1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1473, 1473, 1473, 1473, 1476, 1476, 1476, 1476, 1476,
+     1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476,
+     1476, 1476, 1476, 1476, 1478, 1478, 1478, 1478, 1478, 1478,
+     1479, 1479, 1479, 1480, 1476, 1476, 1604, 1605, 1604, 1604,
+     1604, 1606, 1607, 1604, 1607, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1608, 1609,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1607,
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1610, 1610,
+     1610, 1610, 1610, 1610, 1611, 1611, 1611, 1612, 1607, 1607,
+      451,  451, 2915, 1393,  452,  452, 1713, 1394, 2541, 2915,
+     1714, 2915, 2541, 1713, 2002, 1872,  738, 1714, 2002, 1555,
+      878,  453, 2915, 1726,  879, 2915, 2915, 1727, 1723,  450,
+     1966,  450, 1968,  738,  450,  453, 1867,  450, 2915,  450,
+     2915,  450,  450, 1969, 1684,  450,  738,  450, 1972,  450,
+      450,  450, 2915, 2915, 1971, 2915,  450,  450, 2915,  450,
+
+     1873, 1878, 2915,  738,  450, 1878, 1044,  450, 2915, 2915,
+     2915,  454,  454,  454,  454,  454,  454,  455,  455,  455,
+      456, 1685,  453, 1049, 2915, 1686, 1045, 1045, 1045, 1045,
+     1045, 1045, 1046, 1046, 1046, 1047, 1054, 2859, 2106, 2915,
+     2915, 2859,  453, 1050, 1050, 1050, 1050, 1050, 1050, 1051,
+     1051, 1051, 1052, 1044, 2778, 2778, 1055, 1055, 1055, 1055,
+     1055, 1055, 1056, 1056, 1056, 1057, 1926, 2860, 1926, 2915,
+     1925, 2860, 1925, 1045, 1045, 1045, 1045, 1045, 1045, 1046,
+     1046, 1046, 1047, 2915, 2780, 2780, 2915, 1375, 1382, 1375,
+     1382, 2915,  454,  454,  454,  454,  454,  454,  455,  455,
+
+      455,  456, 1360, 1361, 1360, 1360, 1360, 1085, 1362, 1360,
+     1362, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1363, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360,
+     1360, 1360, 1360, 1360, 1360, 1362, 1362, 1362, 1362, 1362,
+     1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362,
+     1362, 1362, 1362, 1362, 1364, 1364, 1364, 1364, 1364, 1364,
+     1365, 1365, 1365, 1366, 1362, 1362, 2915,  451, 2915, 1100,
+      450,  452,  450, 1101, 2915, 2218, 2915, 1979, 1994, 2012,
+
+     2915, 1979, 1994, 2915, 1787, 2915, 2030, 2230, 1787, 2915,
+     2030, 2041, 2915, 2915, 2915,  450, 2014,  450,  453,  453,
+     2915, 2915, 1975,  450, 2196,  450, 1784,  453, 2915, 1409,
+     1973,  450, 2915,  450, 2210, 2915, 2915,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915,  450,  450, 1370, 1371,
+     1370, 1370, 1370, 1372, 1373, 1370, 1373, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1374,
+     1375, 1376, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1377, 1377, 1377, 1377, 1377, 1377, 1378, 1378, 1378, 1379,
+     1373, 1373, 1401, 1402, 1401, 1401, 1401, 1104, 1403, 1401,
+     1403, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+     1401, 1401, 1401, 1401, 1404, 1105, 1401, 1401, 1401, 1401,
+     1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+     1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401,
+
+     1401, 1401, 1401, 1401, 1401, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1403, 1403, 1405, 1405, 1405, 1405, 1405, 1405,
+     1406, 1406, 1406, 1407, 1403, 1403, 1410, 1411, 1410, 1410,
+     1410, 1412, 1413, 1410, 1413, 1410, 1410, 1410, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1414,  450,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410,
+     1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1413,
+     1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413,
+
+     1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1415, 1415,
+     1415, 1415, 1415, 1415, 1416, 1416, 1416, 1417, 1413, 1413,
+     1418, 1419, 1418, 1418, 1418, 1420, 1421, 1418, 1421, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1422, 1423, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418,
+     1418, 1418, 1418, 1421, 1421, 1421, 1421, 1421, 1421, 1421,
+     1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421,
+     1421, 1421, 1424, 1424, 1424, 1424, 1424, 1424, 1425, 1425,
+
+     1425, 1426, 1421, 1421, 1732, 1733, 1732, 1732, 1732, 1436,
+     1734, 1732, 1734, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1732, 1732, 1732, 1732, 1732, 1732, 1735, 1732, 1732, 1732,
+     1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1736, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1732, 1737, 1732, 1732, 1732, 1732, 1732, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1738, 1738, 1738, 1738,
+     1738, 1738, 1739, 1739, 1739, 1740, 1734, 1734, 1473, 1474,
+     1473, 1473, 1473, 1475, 1476, 1473, 1476, 1473, 1473, 1473,
+
+     1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1477,  450, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473,
+     1473, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476,
+     1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476,
+     1478, 1478, 1478, 1478, 1478, 1478, 1479, 1479, 1479, 1480,
+     1476, 1476, 1864, 1865, 1864, 1864, 1864, 1555, 1866, 1864,
+     1866, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864,
+     1864, 1864, 1864, 1864, 1867, 1864, 1864, 1864, 1864, 1864,
+
+     1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864,
+     1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1868, 1864,
+     1864, 1864, 1864, 1864, 1864, 1866, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1869, 1869, 1869, 1869, 1869, 1869,
+     1870, 1870, 1870, 1871, 1866, 1866, 1604, 1605, 1604, 1604,
+     1604, 1606, 1607, 1604, 1607, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1608, 1609,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1607,
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1610, 1610,
+     1610, 1610, 1610, 1610, 1611, 1611, 1611, 1612, 1607, 1607,
+      738,  451, 1978, 2586, 2915,  452, 1979, 2586,  451, 2915,
+      738,  451,  452,  451, 2061,  452, 2915,  452, 2061, 2915,
+      451, 2042, 2915, 2336,  452, 2042, 1977, 2915, 2915,  450,
+      450, 2915, 2915, 2915, 1981,  453,  450,  450,  450,  450,
+      738,  450, 2915, 1454,  450,  450,  450,  450,  450,  450,
+     1044,  738,  450, 1982, 1980,  450,  450,  450, 2915, 2915,
+
+     1320, 2915, 2231, 2915,  450, 2915, 2915, 2915, 2915, 2915,
+     1045, 1045, 1045, 1045, 1045, 1045, 1046, 1046, 1046, 1047,
+     1321, 1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322, 1323,
+     1325,  738, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2835, 1330,  738,  451, 2835, 2915, 2915,  452, 2915, 2915,
+     1326, 1326, 1326, 1326, 1326, 1326, 1327, 1327, 1327, 1328,
+     2730, 1331, 1331, 1331, 1331, 1331, 1331, 1332, 1332, 1332,
+     1333,  450,  738, 1928, 2045, 2915,  507, 1928, 2045,  450,
+     2835, 1335,  738, 2915, 2835, 2915, 2915,  450, 2915, 2052,
+     2149, 2149, 1335, 2052,  453, 2150, 1472, 2915, 2915, 2915,
+
+     2730, 1336, 1336, 1336, 1336, 1336, 1336, 1337, 1337, 1337,
+     1338, 1594, 1336, 1336, 1336, 1336, 1336, 1336, 1337, 1337,
+     1337, 1338, 1341,  738, 2915, 2915, 2915, 2915, 2915, 2915,
+     2237, 2915, 1346,  738,  451, 2915, 1745, 2915,  452, 2915,
+     1746, 2915, 1342, 1342, 1342, 1342, 1342, 1342, 1343, 1343,
+     1343, 1344, 1347, 1347, 1347, 1347, 1347, 1347, 1348, 1348,
+     1348, 1349,  450,  738,  450, 2094, 2915, 2042, 2915,  452,
+      450, 2042,  450, 1351,  738, 2915, 2915, 1985,  450, 2915,
+      450, 2915, 2915, 1044, 1453, 1453, 2095,  451, 2915, 1454,
+     2915,  452, 2915, 1352, 1352, 1352, 1352, 1352, 1352, 1353,
+
+     1353, 1353, 1354, 1045, 1045, 1045, 1045, 1045, 1045, 1046,
+     1046, 1046, 1047, 1044,  738,  450, 1988, 2915, 2915, 2915,
+     2915, 2915, 2915,  450, 1320,  738, 1745, 2915, 2915, 2915,
+     1746,  450, 2915, 1045, 1045, 1045, 1045, 1045, 1045, 1046,
+     1046, 1046, 1047, 2915, 1321, 1321, 1321, 1321, 1321, 1321,
+     1322, 1322, 1322, 1323,  450,  738, 2052, 2239, 2915, 2915,
+     2052, 2240,  450, 1986, 1325,  738, 2915, 2915, 2915, 2915,
+      450, 2915, 2322, 1593, 1593, 1330, 2323, 2241, 1594, 1609,
+     2915, 2915, 2915, 2915, 1326, 1326, 1326, 1326, 1326, 1326,
+     1327, 1327, 1327, 1328, 1382, 1331, 1331, 1331, 1331, 1331,
+
+     1331, 1332, 1332, 1332, 1333, 1320,  738, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 1320,  738,  451, 2915, 1120,
+     2915,  452, 2915, 1121, 2915, 1321, 1321, 1321, 1321, 1321,
+     1321, 1322, 1322, 1322, 1323, 1321, 1321, 1321, 1321, 1321,
+     1321, 1322, 1322, 1322, 1323,  450,  738,  450, 2068, 2915,
+     2089, 2915, 2068,  450, 2089,  450, 1654,  738, 2915, 2915,
+     1989,  450, 2915,  450, 2915, 2915, 1659, 2915, 2072,  453,
+     1993,  453, 2091, 2915, 1994, 2915, 1655, 1655, 1655, 1655,
+     1655, 1655, 1656, 1656, 1656, 1657, 1660, 1660, 1660, 1660,
+     1660, 1660, 1661, 1661, 1661, 1662, 1664,  738,  450, 2915,
+
+     2915, 2915, 2915, 2915, 2915, 2915,  450, 1341,  738, 1752,
+     2915, 2915, 2915, 1753,  450, 2915, 1665, 1665, 1665, 1665,
+     1665, 1665, 1666, 1666, 1666, 1667, 2915, 1342, 1342, 1342,
+     1342, 1342, 1342, 1343, 1343, 1343, 1344,  450,  738, 2254,
+     2230, 2915, 2915, 2254, 2041,  450, 1991, 1341,  738, 2915,
+     2915, 2915, 2915,  450, 2915, 2915, 2915, 2915, 1669, 1824,
+     2915, 1756, 1409, 2915, 2915, 1757, 2915, 1342, 1342, 1342,
+     1342, 1342, 1342, 1343, 1343, 1343, 1344, 2255, 1670, 1670,
+     1670, 1670, 1670, 1670, 1671, 1671, 1671, 1672, 1674,  450,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915,  450, 1679, 2915,
+
+     2915, 2915,  451, 2915, 2915,  450,  452, 2915, 1675, 1675,
+     1675, 1675, 1675, 1675, 1676, 1676, 1676, 1677, 1680, 1680,
+     1680, 1680, 1680, 1680, 1681, 1681, 1681, 1682,  451,  451,
+      450, 1996,  452,  452, 2915, 1759, 2915, 2271,  450, 1760,
+      451, 2098, 2915, 2915,  452, 2915,  450,  451, 2915,  453,
+     2915,  452, 2001, 2915,  894, 2915, 2002,  450, 1867, 2915,
+     2152, 2915, 2915, 1761, 2152,  450, 1940, 2915,  450, 1997,
+     2915,  450, 2915,  450, 2153,  450,  450, 1762, 1931,  450,
+      450,  453, 2915,  450,  450, 2915, 2915, 2915,  450, 1128,
+     1998,  450, 2915, 1129, 2915, 1608,  450, 2915, 2915,  454,
+
+      454,  454,  454,  454,  454,  455,  455,  455,  456, 1685,
+     1768, 1130,  451, 1686, 1769,  451,  452,  450, 2915,  452,
+     2200, 2915, 1774, 2915, 2200,  450, 1775, 1452, 1452, 2915,
+      453, 2003, 1774,  450, 2915, 2004, 1775, 1941,  450, 2915,
+      450,  453, 2915,  450, 2915, 1942,  450, 2915,  450, 2915,
+      450,  450, 2915, 1943,  450, 2005,  450, 2242,  450,  450,
+      450, 2240, 2915, 2915, 2007, 2915,  450, 2915,  450, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915,  450, 2243, 1608, 1614,
+      454,  454,  454,  454,  454,  454,  455,  455,  455,  456,
+     1370, 1689, 1370, 1370, 1370, 1690, 1373, 1370, 1373, 1370,
+
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1375,  450, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370,
+     1370, 1370, 1370, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 1373, 1377, 1377, 1377, 1377, 1377, 1377, 1378, 1378,
+     1378, 1379, 1373, 1373, 1732, 1733, 1732, 1732, 1732, 1436,
+     1734, 1732, 1734, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1732, 1732, 1732, 1732, 1732, 1732, 1735, 1732, 1732, 1732,
+
+     1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1736, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+     1732, 1737, 1732, 1732, 1732, 1732, 1732, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1738, 1738, 1738, 1738,
+     1738, 1738, 1739, 1739, 1739, 1740, 1734, 1734, 2915,  451,
+     2915, 1146,  450,  452,  450, 1147, 2915, 2218, 2915, 2915,
+     2173, 2012, 2383, 2915, 2173, 2266, 2383, 2389, 2239, 2266,
+     2271, 2389, 2240, 2915, 2098, 2915, 2915,  450, 2014,  450,
+     2336, 2176, 2915, 2915, 2028,  450,  453,  450, 2241, 2150,
+
+     1609, 1867, 2008,  450, 2915,  450, 2915, 2915, 2915,  450,
+      450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+      450,  450,  450,  450,  450,  450,  450,  450, 1782, 2254,
+     2915, 2242, 1783, 2254, 2915, 2240, 2915, 2242,  450,  450,
+     2284, 2240, 2287, 2322, 2284, 2915, 2287, 2323, 2915, 1824,
+     1784, 2243, 1608, 1614, 2915, 2915,  450, 2243, 1608, 1614,
+     2399,  453, 2915,  453,  450, 1382, 2915, 2915, 2915, 2915,
+     2915, 2915,  450, 2010, 2011, 2010, 2010, 2010, 2012, 2013,
+     2010, 2013, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010, 2014,  450, 2010, 2010, 2010,
+
+     2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010, 2010, 2013, 2013, 2013, 2013,
+     2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013,
+     2013, 2013, 2013, 2013, 2013, 2015, 2015, 2015, 2015, 2015,
+     2015, 2016, 2016, 2016, 2017, 2013, 2013, 1782, 2322, 2915,
+      451, 1783, 2323, 2338,  452, 2915, 2915, 2338, 2915,  912,
+     2383, 2915, 1798,  913, 2383, 2915, 1799, 2471, 2915, 1784,
+     1382, 2471, 2029, 2915, 2176,  450, 2030, 2915,  450, 2915,
+     2915,  451, 2028,  450, 1800,  452,  450,  450,  453, 2915,
+
+      450,  450, 2020, 2013,  450,  450, 2021, 2010,  450, 2010,
+      450, 2389, 2915, 2027, 2563, 2389,  450, 2440,  450,  450,
+     2461, 2440, 2915, 2010, 2461, 2915,  450,  450, 2149, 2149,
+     2915, 2915, 2473, 2150, 2033,  450, 2473, 2915,  453, 2915,
+     2915,  453, 2915, 2915, 2915, 2915, 2915, 2535, 2915, 2915,
+     2553, 2915, 2915,  453, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
+     2010, 2010, 2010, 2010, 2010,  451,  451, 1128, 2915,  452,
+      452, 1129, 2915, 2915, 2915, 2915,  451, 2446,  451,  451,
+
+      452, 2446,  452,  452, 2915, 2915, 2915, 2509, 1825, 1130,
+     2031, 2509, 1826,  450,  450,  450, 2035, 2915,  453, 2034,
+     2915,  450,  450,  450,  450, 2036,  450,  450,  453,  450,
+      450,  450,  450, 1263,  450, 2037,  450, 1264, 2915, 1220,
+      450, 2540,  450,  450,  450, 2056, 2915,  451, 2915, 2057,
+     1834,  452,  450, 2915, 1835, 1265, 2915, 2915, 2915, 2060,
+     2067,  450, 2038, 2061, 2068, 1512, 2915, 2915, 2915,  450,
+      451, 2915,  451,  450,  452,  450,  452,  450,  450, 2915,
+     1090,  450, 2915,  450, 2915, 2065,  450,  450,  450,  450,
+     2058,  450, 2062,  451,  450,  450,  450,  452,  450, 2915,
+
+      450, 2915, 2915,  450,  450,  451,  450, 1206,  450,  452,
+     2915, 1207, 2915, 2915,  450, 2069,  450, 2915, 1209,  451,
+     2915,  450, 1210,  452, 2915, 2915, 2915, 2915, 2070,  450,
+      451, 2915, 2915,  450,  452,  450, 2081,  450, 2042, 2915,
+     2915,  450, 2042,  450, 2082, 2915,  450,  450, 2079,  450,
+     2915,  450,  451, 2088,  450,  450,  452, 2089,  450, 2084,
+     1454, 2915,  450,  450,  451, 2052,  450, 2915,  452, 2052,
+     2915, 2915, 2042,  451,  450, 2090, 2042,  452,  451, 2915,
+      450,  450,  452, 2915, 2486, 2915, 2915, 1594,  450,  450,
+     2915, 2915,  450, 2915, 1454, 2085,  450,  450, 2592, 2621,
+
+      450,  450, 2592, 2622, 2915, 2915,  450, 2092,  450,  450,
+     2574, 2490, 2915, 2915,  450, 2096, 2915,  450, 2915, 2915,
+     1241, 1614,  450, 1864, 1865, 1864, 1864, 1864, 1555, 1866,
+     1864, 1866, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864,
+     1864, 1864, 1864, 1864, 1864, 1867, 1864, 1864, 1864, 1864,
+     1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864,
+     1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1864, 1868,
+     1864, 1864, 1864, 1864, 1864, 1864, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1866, 1869, 1869, 1869, 1869, 1869,
+
+     1869, 1870, 1870, 1870, 1871, 1866, 1866, 2097, 2915,  451,
+     1222, 2098, 1877,  452, 1223, 2915, 1878, 2915, 2915,  451,
+     2568,  452,  451,  452, 2568,  452,  452, 2915, 2915,  451,
+     2915, 2915, 2099,  452, 2915,  450, 2915,  450,  450, 2104,
+      450,  453,  453,  450, 2915,  450,  450,  450,  450, 2105,
+      450,  450, 2102,  450,  450,  450,  450,  450,  450, 2915,
+     1234, 2915, 2915, 2107, 1235,  450,  450,  451, 2108, 2915,
+      451,  452,  451,  450,  452, 2915,  452,  451, 2915, 1243,
+     2915,  452, 2111, 1244, 2915, 2915, 2915, 2042,  450,  953,
+      451, 2042, 2915,  954,  452,  450,  450, 2052,  450, 2915,
+
+      450, 2052, 2113,  450,  450,  450,  450,  450,  450, 1454,
+     2915,  450, 2112, 2114,  450,  450,  450,  450,  450, 1594,
+      451,  450, 2117,  450,  452,  450,  450,  451, 2645, 2915,
+     2118,  452,  451,  450,  450, 2581,  452,  451,  451, 2915,
+     2590,  452,  452, 2915, 2590, 2915, 2915, 2592,  450,  451,
+     2621, 2592, 2915,  452, 2622, 2120,  450, 2915, 2915, 2915,
+      450,  453, 1241,  450, 2119,  450,  450, 2124,  450, 1241,
+     2121,  450, 1614,  450,  450, 2122,  450,  450, 2915, 1909,
+      451, 2123,  450, 1910,  452,  450, 2125, 2915, 2126, 2915,
+      451, 1255, 2572,  450,  452, 1256, 2572,  451, 2915, 2764,
+
+     2619,  452,  451, 2764, 2619, 2915,  452,  450,  450, 2139,
+     2915, 2915, 2915,  453, 2915,  450,  450, 2137,  450,  450,
+      453,  453, 2915,  450,  450,  450,  450,  450, 2140, 2644,
+      450, 2145, 1918,  450,  450,  450, 1919, 2686,  450, 1263,
+     2141,  450, 2915, 1264,  451, 2915,  450, 2621,  452, 1592,
+     1592, 2622, 2915, 2915, 2915, 2915, 2915, 2915, 2151, 2915,
+      450, 1265, 2152, 2915, 2915, 2915, 2915,  450,  450, 1614,
+      451, 2915,  450, 1927,  452,  450,  450, 1928, 2783, 2915,
+      450, 2143, 2783,  450, 2915, 2144,  450, 2147,  450, 2784,
+     2148, 2148, 2665, 2784,  450, 1929, 2665, 2915,  450,  453,
+
+     2091,  450,  450, 2915, 2915, 2154,  450, 2915, 2915,  450,
+     2915, 2091, 2730,  453,  450, 2915, 2915,  450, 1604, 1930,
+     1604, 1604, 1604, 1931, 1607, 1604, 1607, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1608,  450, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604,
+     1604, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,
+     1610, 1610, 1610, 1610, 1610, 1610, 1611, 1611, 1611, 1612,
+
+     1607, 1607,  451, 2915,  991,  451,  452,  451,  992,  452,
+     2915,  452, 2915, 2732, 2042, 2915, 2764, 2732, 2042,  451,
+     2764, 2915, 2042,  452,  451, 2915, 2042, 2915,  452, 2915,
+      450, 2915,  450,  450,  453,  450, 1454,  453,  450, 2157,
+      450,  450, 2708,  450, 1454, 2159,  450,  450,  450, 2158,
+     1084,  450,  450,  509, 1085,  450, 2915,  451, 2160, 2915,
+      450,  452,  451,  450, 2768, 2915,  452, 2821,  450,  451,
+     2042, 2821, 2915,  452, 2042,  451, 2915, 2915,  450,  452,
+     2052, 2915, 2915, 2915, 2052,  450,  450, 2052, 2915, 2822,
+      450, 2052, 1454,  450,  450, 2165, 2783,  450,  450, 2164,
+
+     2783,  450, 1594,  450, 2915,  450,  450, 2915, 2169, 1594,
+     2915,  450, 2167,  450, 2915, 2715, 2915,  453, 2091,  450,
+     2171, 2172, 2171, 2171, 2171, 2173, 2174, 2171, 2174, 2171,
+     2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171,
+     2171, 2175, 2176, 2171, 2171, 2171, 2171, 2171, 2171, 2171,
+     2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171,
+     2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171, 2171,
+     2171, 2171, 2171, 2174, 2174, 2174, 2174, 2174, 2174, 2174,
+     2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174,
+     2174, 2174, 2177, 2177, 2177, 2177, 2177, 2177, 2178, 2178,
+
+     2178, 2179, 2174, 2174,  451, 1701,  451, 2784,  452, 1702,
+      452, 2784, 2915, 2915, 2052, 1704, 2052,  451, 2052, 1705,
+     2052,  452, 2915, 2915, 1707, 2915,  451, 1393, 1708, 2091,
+      452, 1394,  450,  450,  450, 2182, 1594, 2180, 1594, 2915,
+      450,  450,  450,  450, 2184,  450, 2185, 2915,  450,  450,
+      450,  450,  450,  450,  450,  450, 2774, 2652, 2915,  450,
+      450,  450,  450,  450, 2189, 2915, 2915, 2915,  450, 2187,
+      450,  450,  451, 2915, 1713,  451,  452,  451, 1714,  452,
+     2915,  452, 2915, 2808, 2851, 2915, 1100, 2808, 2852,  451,
+     1101, 2915, 2915,  452, 2828, 2915, 2915, 2915, 2828, 2915,
+
+      450, 2190,  450,  450,  453,  450, 2812, 2915,  450, 2915,
+      450,  450, 2192,  450,  450,  453,  450,  450,  450,  450,
+     1978,  450,  450, 2193, 1979,  450, 2915, 2197, 2915, 2915,
+      450, 2198, 2194,  450, 2199, 2915, 2915,  451, 2200,  451,
+      451,  452, 2915,  452,  452, 2849,  451, 2195,  450, 2849,
+      452, 2915, 2915, 2915, 2915,  450,  450, 2821, 2915, 2915,
+     2915, 2821,  450,  450,  450,  450,  453,  450,  450, 2204,
+      450,  450,  871,  450,  450,  450,  450, 2915,  450, 2822,
+     2915,  450,  450,  450,  450,  451, 2201,  451, 2915,  452,
+      450,  452, 1993, 2915,  451, 2851, 1994,  451,  452, 2852,
+
+     2915,  452, 2915, 2915, 2915, 2852, 2001,  451, 2915, 2852,
+     2002,  452, 2206,  450, 2915,  450, 2207, 2812, 2915, 2915,
+      450,  450,  450,  450, 2915,  450, 2816, 2211, 2209,  450,
+      450,  450, 2212,  450,  450,  450,  450, 2915,  450, 2915,
+      451,  450,  450,  450,  452, 2915, 2915, 2915, 2915, 1128,
+      450,  450,  451, 1129,  451, 2915,  452, 2915,  452, 2915,
+     2915,  451, 2915,  451, 2915,  452,  912,  452,  450, 2915,
+      913, 1130, 2915, 2215, 2915, 2029,  450,  450, 2915, 2030,
+      450, 2915,  450, 2217,  450,  450, 2915, 2216,  450,  450,
+      450,  450, 2915,  450,  450, 2915,  450,  450,  450,  450,
+
+      451, 2915,  450,  450,  452,  450, 2915,  450, 2219,  451,
+      450,  450,  451,  452, 2915, 2915,  452, 2915,  451,  450,
+     2814, 2915,  452, 2915, 2814, 2915, 2915, 2221,  450, 1128,
+      451, 2915, 2915, 1129,  452, 2915,  450,  450, 2915, 1263,
+      450, 2816, 2822, 1264,  450,  450,  450, 2915,  450, 2224,
+     2223, 1130, 2915,  450,  450, 2226,  450,  450,  450,  451,
+     2060, 1265,  450,  452, 2061,  450,  450,  450, 2915, 2915,
+     2225, 2915, 2060,  450,  450,  450, 2061, 2198,  451, 2915,
+     2227, 2198,  452,  450, 2915, 2915, 2915,  450,  450, 2915,
+     2067, 2915, 2915, 2915, 2068,  450,  450,  451,  453, 2915,
+
+      450,  452, 2355,  450,  450, 2915,  450, 1510,  450, 2244,
+     1090, 1511, 2915, 2246,  450, 2915,  450, 2247,  450,  451,
+     2915, 2356, 2248,  452, 2249,  450,  450, 1512, 1206, 2915,
+     2915, 2915, 1207,  450,  450,  450, 2915, 2915, 2250, 2915,
+      451,  450, 2915,  450,  452, 2251,  451,  450, 2915,  451,
+      452,  450, 2915,  452, 2915,  450,  450, 2915, 2088, 2915,
+     2915, 2265, 2089,  450,  450, 2266, 2915, 2259,  450, 2915,
+     2915, 2262,  450, 2915,  450, 2915,  450,  450, 2915, 2261,
+     2090, 2915,  450,  451,  450,  450,  450,  452, 2915,  450,
+      450, 2915,  451,  450,  450, 2915,  452,  450, 2915, 2915,
+
+     2915, 2915,  450, 2097,  451,  450, 1222, 2098,  452,  451,
+     1223,  450, 2915,  452, 2915, 2915, 2268, 2915,  451,  450,
+      450,  451,  452, 2915, 2915,  452, 2915,  450,  450, 2915,
+     2915,  450,  450, 2915,  450, 2269,  450,  450, 2275,  450,
+      450, 2915,  450, 2915, 2272,  450,  450,  450,  450,  450,
+      450,  451,  451,  450,  450,  452,  452,  450, 2915, 2915,
+     2915, 2277,  450, 2286, 2283, 2278, 2915, 2287, 2284, 2915,
+     1243, 2915, 2915,  451, 1244, 2915, 2915,  452, 2915,  450,
+      450, 2915,  451, 2915, 2915, 2282,  452,  450,  450, 2288,
+     2915,  450,  450, 2915, 2281,  450,  450, 2285,  450,  450,
+
+      450,  450, 2915, 2915, 2915, 2915,  450,  450,  450,  450,
+      450,  451, 2915, 2915, 2293,  452,  451, 2294,  450, 2295,
+      452,  451, 2915, 2915, 2915,  452,  450, 2915,  451, 2915,
+     2915,  451,  452, 2717, 2915,  452, 2915, 2717, 2915,  450,
+     2296,  451,  451, 2915,  450,  452,  452,  450, 2915,  450,
+     2776, 2776,  450, 2915,  453,  450,  450,  450, 2298,  450,
+      450, 2915, 2297, 2299,  450,  450, 2301,  450, 2915,  450,
+      450, 2300,  450, 2915, 2915,  450,  451,  450,  450,  451,
+      452, 2302, 2915,  452, 2915,  450,  450, 2915, 1255, 2915,
+      451, 1263, 1256, 2915,  452, 1264, 2915,  451, 2915, 2915,
+
+     2915,  452, 2915, 2915,  450, 2915, 2915, 2314, 2915, 2915,
+     2312, 2915,  450, 1265, 2915,  450,  450, 2315,  450,  450,
+      450, 2915, 2915,  450,  450,  450,  450,  450, 2915, 2317,
+     2316, 2915,  450,  450,  450,  450,  451, 2915,  451,  451,
+      452,  450,  452,  452, 2915, 2151, 2915, 2915,  991, 2152,
+     2915, 2915,  992, 2915, 2915, 2915, 2148, 2148, 2915,  451,
+     2915, 2915, 2915,  452,  450,  451,  450,  450, 2915,  452,
+     2915, 2915,  450,  450,  450,  450,  450, 2915, 2915, 2318,
+      450,  450,  450,  450,  450, 2915, 1996,  450, 2915,  450,
+      451, 2915, 2325,  450,  452,  450, 2719, 2321, 2721, 2915,
+
+     2719,  450, 2721,  450, 2915, 2915, 2915, 2326, 2915,  450,
+     2915, 2915, 2915, 2778, 2778, 2780, 2780,  453,  450,  453,
+     2915, 2915, 2915, 2915, 2915, 2915,  450, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915,  450, 2915,  883,  973,  974,  973,
+      973,  973,  975,  976,  973,  976,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  977,  978,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      973,  973,  973,  973,  973,  973,  973,  973,  973,  973,
+      976,  976,  976,  976,  976,  976,  976,  976,  976,  976,
+
+      976,  976,  976,  976,  976,  976,  976,  976,  976,  980,
+      980,  980,  980,  980,  980,  981,  981,  981,  982,  976,
+      976,  451,  451,  451,  451,  452,  452,  452,  452, 2915,
+     2915, 2915, 2915,  451, 2915, 2915, 2915,  452, 2915, 2915,
+     2915, 2915,  451, 2915, 2915, 2915,  452, 2915, 2332,  450,
+      450,  450,  450, 2915, 2915, 2334, 2915,  450,  450,  450,
+      450,  450, 2915,  871, 2330,  450,  450,  450,  450,  450,
+      450,  451, 1704, 2339, 2915,  452, 1705,  450,  450, 2915,
+     2915,  451, 2915,  451, 2915,  452,  450,  452, 2915, 2915,
+     2915, 2915,  451, 1393, 1713, 2915,  452, 1394, 1714,  450,
+
+      450, 2915, 2915, 2915, 2915, 2915, 1100,  450,  450,  450,
+     1101,  450, 2915, 2915, 2341,  450,  450,  450, 2345,  450,
+      450,  450, 2348, 2915, 2343,  450, 2915,  450,  450,  450,
+      450, 2915, 2915, 2915,  450, 2346,  450,  450,  450, 2349,
+      451, 2915,  450,  451,  452, 2197, 2915,  452, 2915, 2198,
+      450, 2915, 2199, 2915,  451, 2915, 2200,  451,  452, 2915,
+     2915,  452, 2915,  451, 2915, 2915, 2915,  452,  450, 2350,
+     2353,  450, 2915,  450,  451, 2915,  450, 2915,  452, 2351,
+      450,  450,  450, 2357,  450,  450, 2915,  450,  450, 2354,
+      450,  450, 2915,  450, 2915, 2915,  450, 2915,  450,  450,
+
+     2360,  450,  450, 2915,  451,  451, 2362,  450,  452,  452,
+      450, 2915, 2915, 2915, 2915,  451,  451, 2363,  450,  452,
+      452, 2915, 1140, 2915, 2915, 2915, 1141, 2915, 2915, 2365,
+     2915, 2915,  450,  450, 2915, 1128, 2915, 2915, 2367, 1129,
+      450,  450, 2368,  450, 2371, 2915, 2915, 2915,  450,  450,
+      450,  450,  450, 2915, 2915, 2915, 2915, 1130,  450,  450,
+      450,  912, 2915,  450,  451,  913,  450, 2915,  452, 2915,
+     2915,  450, 2915,  451,  451, 2915, 2372,  452,  452,  450,
+     2915, 2915, 2915,  451, 1768, 2915, 1825,  452, 1769,  450,
+     1826, 2915,  450, 2915, 2915, 2915, 2915,  450, 2373, 2377,
+
+      450,  450,  450, 2376, 2915,  450, 2375, 2915,  450,  450,
+      450,  450,  450, 2915,  450, 2915, 2915,  450,  450,  450,
+      450, 1918,  450, 2915, 2915, 1919, 2915,  450,  450, 2915,
+      450, 2060, 2915,  451, 2915, 2061, 2378,  452,  451, 2915,
+      451, 2915,  452, 2915,  452, 2915, 2915, 2915, 2915,  450,
+      451, 2915, 2915, 2915,  452, 2915, 2915,  450, 2915,  450,
+     2390,  450, 2915, 2393, 2915,  450,  450,  450,  450,  450,
+     2915, 2392, 2915, 2915,  450,  450,  450,  450,  450, 2394,
+     2915,  451,  450, 2915,  450,  452,  450, 1510, 2395, 2915,
+     2915, 1511,  451, 2915,  450, 2915,  452, 2915, 2915,  451,
+
+     2915, 2915,  451,  452, 2915, 2915,  452, 1512, 2915,  450,
+     2915, 2915, 2265, 2915, 2396,  450, 2266,  450, 2397, 2915,
+      450, 2915, 2915,  450, 2915,  450, 2401,  450,  450, 2404,
+      450,  450, 2403,  451, 2915,  450,  450,  452,  450, 2915,
+      450, 2915, 2915,  450, 2915,  451,  450, 2097,  450,  452,
+      451, 2098, 2915, 2915,  452, 2915,  450, 2915, 2407,  451,
+     2408,  450,  451,  452, 2915, 2915,  452, 2915,  451,  450,
+     2915, 2915,  452,  450, 2915,  450, 2915,  450,  450, 2915,
+     2409,  450, 2915,  450, 2915, 2915,  450,  450,  451,  450,
+      450,  450,  452, 2411,  450,  450,  450, 2415,  450, 2915,
+
+     2915, 2915, 2915,  450,  450, 2413,  450, 2283, 2915, 2915,
+     2283, 2284,  450, 2286, 2284, 2915,  450, 2287, 2915, 2915,
+     2915, 2915, 2286, 2915,  450, 1243, 2287, 2915, 2915, 1244,
+     2915, 2915,  450, 2915, 2915,  450, 2915, 2416,  450, 2915,
+     2915,  450, 2915,  450,  451, 2915,  450, 2417,  452,  450,
+      450,  450, 2915,  450,  450,  451, 2915,  450,  450,  452,
+     2418,  450, 2915, 2915, 2915, 2915,  450,  451, 2421,  450,
+     2915,  452,  450, 2915, 2915, 2915, 2915, 2422, 2915, 2915,
+      450,  451, 2423,  450, 2915,  452,  451, 2915,  450, 2915,
+      452,  450,  451,  451, 2915,  450,  452,  452,  451,  450,
+
+     2915, 2426,  452,  450, 2424, 2915, 2915, 2915, 2915,  450,
+     2425,  450,  451, 2915,  450,  451,  452,  450, 2915,  452,
+      450,  450,  450, 2915, 2915,  450,  450,  963,  450,  450,
+      450, 2915, 2915, 2915, 2428, 2439,  450, 2427, 2915, 2440,
+      450, 2429,  450,  450, 2915, 1255,  451, 2915,  450, 1256,
+      452,  450, 2915, 2915, 2915, 2915,  450,  451, 1263,  450,
+      451,  452, 1264,  450,  452, 2915, 2915, 2915, 2915, 2915,
+     2915,  450,  991,  450, 2441, 2915,  992, 2915, 2915,  450,
+     1265,  450,  450, 2445, 2915,  450,  450, 2446,  450,  450,
+      450,  987, 2915,  450,  450, 2915,  450, 2915, 2915, 2442,
+
+      450,  450,  450,  451,  450,  451,  451,  452,  450,  452,
+      452,  450, 2915, 2915, 2444, 2915,  450,  451,  451,  450,
+      451,  452,  452, 2915,  452, 2915, 2915,  450, 2449, 2915,
+     2915,  450, 2450,  450,  450, 2915, 2915, 2915, 2915,  450,
+     1393,  450, 2452, 2915, 1394,  450,  450,  450,  450,  450,
+      450,  451, 2915, 2455,  450,  452,  450, 2915, 2915, 2915,
+     2915,  450,  450, 1713,  450, 1100, 2460, 1714,  450, 1101,
+     2461, 2915, 2915, 2915, 2915, 2915,  450, 2915, 2915,  450,
+     2915, 2915, 2915, 2457,  450, 2915, 2915,  450,  451, 2915,
+     2915,  450,  452,  450,  450,  450, 2915, 2915, 2915,  450,
+
+      451,  450,  450, 2915,  452, 2915, 2915, 2458, 2915,  450,
+      450,  451, 2915, 2462, 2459,  452,  450, 1113,  451, 2915,
+     2915, 1114,  452, 2470,  450, 2915, 2915, 2471,  450, 2472,
+     2915, 2915,  450, 2473, 2915, 2915, 2464, 2915,  451,  450,
+     2915, 2915,  452, 2915,  450,  450,  450,  450, 2465, 2915,
+     2915,  450,  451,  450,  450,  450,  452,  450, 2915,  450,
+     2915,  450,  450, 2915,  451,  450,  450,  450,  452, 2915,
+     2915, 2915, 2915,  450,  450, 2477, 2915,  451, 2915, 2475,
+      450,  452,  450, 2915, 2915, 2915,  451, 1128,  450,  451,
+      452, 1129,  450,  452, 2915, 2915,  450, 2915, 2478,  451,
+
+      450, 2915, 2915,  452, 2915,  450, 2481, 2915,  450, 1130,
+     2915, 2915, 1128,  450,  450, 2482, 1129,  450, 2915, 2915,
+     2915,  450,  450,  450, 1263,  450, 2915, 1972, 1264, 2915,
+      450,  450, 2915,  450, 1130,  450, 2483, 2060,  451, 2915,
+      450, 2061,  452,  450, 2915, 2915, 1265,  451,  450,  451,
+      451,  452,  450,  452,  452, 2915,  450, 2915, 2004,  451,
+      450, 2915, 2915,  452, 2915, 2491,  450, 2915,  450, 2915,
+     2144, 2915, 2915,  450,  450,  450, 2915,  450,  450, 2915,
+     2494,  450,  450,  450, 2493,  450,  450,  450, 2495, 2915,
+     2915,  450, 1510,  450,  450,  450, 1511, 2497,  451, 2915,
+
+     2496,  451,  452,  450,  451,  452, 2915,  451,  452, 2915,
+     2915,  452, 1512, 2915, 2915, 2915, 2915, 2915,  451, 2097,
+      450, 2508,  452, 2098, 2915, 2509,  450, 2915,  450,  450,
+     2915, 2915,  450, 2915,  450,  450,  450,  450, 2500, 2504,
+      450, 2501,  450,  450, 2506,  450,  450,  450,  450,  450,
+     2915,  450,  451, 2915,  450,  450,  452,  450, 2915, 2915,
+     2505, 2915,  450,  450,  451,  450,  451, 2915,  452, 2283,
+      452, 2286, 2915, 2284, 2915, 2287, 2915, 2915, 2915, 2915,
+      450, 2915, 2915, 2915, 2915, 2915,  451, 2915,  450, 1243,
+      452, 2915,  450, 1244,  450, 2512,  450,  450, 2513,  450,
+
+      450, 2915,  450, 2915, 2915,  450, 2514,  450,  450, 2915,
+      450, 2511,  451,  450,  450,  450,  452,  450, 2517, 2915,
+     2915, 2915,  450,  451,  451,  450, 2915,  452,  452, 2915,
+      450, 2518, 2915,  450,  451, 2915, 2915, 2915,  452, 2915,
+      450, 2915, 2915, 2915, 2915,  451, 2915, 2915,  450,  452,
+     2915,  450,  450, 2915,  451, 2519,  450, 2439,  452,  450,
+      450, 2440,  450, 2915, 2915, 2521, 2520,  450,  450, 2915,
+      450, 2522,  451,  450, 2523,  451,  452, 2915,  450,  452,
+     2524,  450,  450, 2915, 1263,  450, 2915, 2534, 1264,  450,
+      450, 2915, 2915,  450, 2915,  991, 2915, 2915,  450,  992,
+
+      450,  450, 2915,  450, 2536, 2445, 1265, 2915,  450, 2446,
+      451,  450, 2537, 2525,  452, 2915,  450,  451, 2915,  450,
+      450,  452,  451,  450, 2915, 2915,  452, 2915,  450, 2915,
+     2915,  450,  451,  450, 2915, 2915,  452, 2542,  450,  450,
+     2915,  450, 2915, 2915, 1393,  450,  450, 2545, 1394, 2539,
+      450, 2543, 2915,  450,  450, 1713, 2915, 2547,  450, 1714,
+      450,  450, 2915, 2915, 2915, 1100,  450, 2460,  450, 1101,
+      451, 2461,  450, 2549,  452, 2915,  450, 2915, 2915, 2915,
+      450, 2915, 2550,  450, 2915, 2915, 2915, 2915,  450, 2915,
+     2915,  450,  451,  450, 2551,  450,  452, 2552,  450,  450,
+
+     2915,  450, 2915,  450,  451, 2915,  450, 2915,  452,  450,
+     2915,  450, 2915, 2554,  450, 2470, 2915, 2472, 2556, 2471,
+      450, 2473,  451, 2915, 2915, 2915,  452,  451,  450, 2557,
+     2915,  452,  450, 2915, 2567, 2915,  450, 2571, 2568, 2915,
+      450, 2572, 2915,  450, 2915,  450, 2915, 2915,  450, 2915,
+      450,  450, 2562,  450, 2564,  450, 2566, 2915,  450,  450,
+     1128,  450,  450,  450, 1129,  450,  450, 2915, 2915, 2915,
+      450,  450,  451,  450, 2915, 2060,  452, 2915,  450, 2061,
+     2915,  450, 1130, 2915, 2915,  451, 2915,  451,  450,  452,
+     2915,  452, 2915, 2915,  451, 2915,  450,  451,  452, 2915,
+
+      450,  452, 2573,  450,  450, 2915,  451, 2915,  450, 2915,
+      452,  450, 2915,  450, 2582,  450,  450, 2915, 2915,  450,
+      451,  450, 2585,  450,  452,  450, 2584, 2915, 2583,  450,
+      450,  450, 2589,  450,  450, 2588, 2590, 2915,  450,  451,
+     2915,  450,  450,  452, 2915, 2097, 2915, 2915,  450, 2098,
+      450, 2508, 2915, 2593, 1240, 2509,  450,  451,  451, 2915,
+      450,  452,  452, 2915,  450, 2915, 2915,  450,  450, 2915,
+     2283, 2595, 2915,  450, 2284,  450,  450, 2915, 2915,  450,
+     2286,  450, 2594,  450, 2287,  450,  450,  450, 2915,  450,
+     2915, 2915, 1243,  450,  450,  450, 1244, 2915, 2598,  451,
+
+     2597,  450,  450,  452, 2915,  451,  450, 2915,  450,  452,
+     2915,  451, 2915, 2915,  450,  452,  450,  451, 2915, 2915,
+      450,  452,  451, 2915,  450, 2915,  452,  450,  450, 2915,
+     2600, 2915, 2601,  450,  451,  450,  450, 2603,  452,  450,
+     2915,  450, 2915,  450, 2602,  450, 2915,  450,  451,  450,
+      450, 2915,  452,  450, 2915,  450, 2915, 2915,  450,  451,
+     2618, 2604,  450,  452, 2619,  451,  450, 2915, 2915,  452,
+      450, 2605, 2915, 2915, 2607, 2915,  450, 2915,  450, 2915,
+     2915, 2606, 2915, 2915,  450, 1263,  451,  450,  450, 1264,
+      452, 2915,  450,  450, 2915,  450,  450, 2915,  451, 2915,
+
+     2616,  450,  452,  450,  450, 2915, 2915, 1265,  451,  450,
+     2915,  451,  452,  450,  450,  452, 2915, 2915, 2915, 2915,
+      451,  450,  450, 2915,  452, 2623,  450, 2620, 2915,  450,
+      450, 1393, 2625, 1713,  450, 1394,  450, 1714, 2915,  450,
+     2915, 2915,  450, 2915,  450, 1100, 2915,  450,  450, 1101,
+      451, 2915,  450, 2915,  452,  450,  450, 2915, 2915,  450,
+     2915,  450,  451, 2915,  450, 2915,  452,  450,  451,  450,
+     2915, 2915,  452,  450, 2915,  450, 2626,  450,  450,  451,
+      451,  450, 2915,  452,  452, 2627,  450, 2915, 2915,  450,
+      450,  451, 2915,  451,  450,  452,  450,  452,  450, 2915,
+
+     2915, 2631, 2915, 2629,  450, 2915,  450,  450,  450, 2637,
+     2567, 2915,  450, 2571, 2568, 2632,  450, 2572, 2915, 2641,
+     2915,  450, 2915,  450,  450, 2915, 2639,  450,  451,  450,
+     1128, 2915,  452, 2915, 1129,  450, 2915,  450,  450,  451,
+      451,  450, 2915,  452,  452, 2915,  450, 2915, 2915,  450,
+     2643,  451, 1130, 2915,  450,  452,  450,  450,  450, 2915,
+     2915,  451, 2915, 2915,  450,  452,  450,  450,  450, 2653,
+     2915, 2915,  450, 2915,  450,  450,  450, 2915, 2915,  450,
+     2915, 2654, 2656,  450,  450, 2915, 2589,  450, 2915, 2658,
+     2590, 2915, 2655, 2915, 2915,  450,  451,  450,  451, 2664,
+
+      452, 2915,  452, 2665, 2915,  450, 2915, 2915, 1240, 2915,
+     2915, 2915, 2915, 2097,  450, 2915, 2283, 2098, 2915, 2666,
+     2284, 2915,  450, 2915,  450, 2915,  450,  450, 2915, 2915,
+      450, 2915,  450,  451,  450,  450, 2915,  452, 2915, 2661,
+      450,  450,  450,  450,  450, 2660,  451, 2915, 2662,  450,
+      452,  451,  450, 2915, 2915,  452, 2915,  450, 2915, 2915,
+      450,  450, 2915,  451, 2915, 2915, 2915,  452, 2667,  450,
+     2915, 2915, 2915, 2915,  450, 2915,  451,  450, 2915,  450,
+      452,  451,  450, 2915, 2668,  452, 2915,  450, 2915, 2915,
+      450,  450, 2915, 2915, 2669,  450, 2915, 2915,  451,  450,
+
+     2915, 2915,  452, 2915,  450, 2915, 2915, 2670, 2915,  450,
+      451, 2671,  450, 2915,  452,  451, 2915,  450, 2915,  452,
+      450, 2915, 2915, 2915, 2672,  450,  450, 2618, 2915, 2673,
+     2915, 2619, 2915, 2915,  450, 2915, 2915,  451,  450, 2915,
+     2683,  452,  450,  450, 1263, 2915,  450, 2915, 1264, 2689,
+     2915,  450, 2915, 2690, 2674,  450, 1713, 2915,  451,  450,
+     1714, 2915,  452,  450, 2685,  450, 1265, 2915, 2915, 2915,
+      451,  450,  450,  450,  452, 2915, 2687,  450, 2915, 2915,
+      450,  450, 2915, 2691,  450,  450,  450,  451,  450, 2915,
+     2915,  452,  450,  450,  450, 2915, 2915, 2915,  450, 2915,
+
+      450,  451,  450, 2693,  451,  452,  450,  451,  452, 2915,
+     2915,  452, 2915, 2703,  450,  450, 2915, 2704, 2695, 2915,
+     2915, 2915, 2716,  450,  451, 2915, 2717, 2696,  452,  450,
+     2915,  450,  450, 2915,  451,  450, 2915,  450,  452, 2915,
+      450,  450, 2915,  450, 2701,  450, 2915, 2699,  450,  450,
+      450,  450,  450, 2706, 2915, 2718, 2915,  450,  450, 2719,
+      450, 2720,  450, 2915, 2915, 2721,  450, 2723,  450, 2915,
+      450, 2724,  451, 2915, 2915, 2915,  452, 2915,  450, 2915,
+     2915,  451, 2664,  450, 2097,  452, 2665, 2915, 2098,  450,
+     2915,  450, 2915, 2915, 2731,  450, 2915,  450, 2732,  450,
+
+      450, 2726, 2666,  450, 2915,  450, 2915, 2915,  450,  450,
+      450,  450,  450, 2728, 2727,  451,  450,  450,  450,  452,
+      450, 2915,  450, 2915, 2915,  450,  450,  451,  450,  451,
+      450,  452,  451,  452, 2915, 2915,  452, 2915,  450, 2915,
+     2915, 2915, 2915,  450, 2733, 2915,  451, 2915, 2915, 2915,
+      452,  450,  451, 2915, 2915,  450,  452,  450,  451,  450,
+      450, 2915,  452,  450, 2734,  450, 2915, 2915,  450, 2735,
+     2915,  450, 2915,  450,  450,  451,  450,  960, 2915,  452,
+      450,  962,  450, 2915, 2915, 2736,  450,  451,  450, 2915,
+      450,  452, 2915,  451,  450, 2915,  450,  452, 2915, 2915,
+
+     2915, 2915, 2737,  450,  451, 2915,  451, 2915,  452, 2915,
+      452,  450, 2738,  451, 2915,  450, 2915,  452, 2747,  450,
+     2915,  450, 2749,  450,  451, 2915,  451, 2915,  452,  450,
+      452,  450,  450, 2751,  450, 2915, 2915,  450, 2915,  451,
+      450,  450,  450,  452, 2753, 2915, 2915, 2915,  450,  450,
+      450,  451,  450, 2915,  450,  452, 2915,  450, 2915, 2915,
+      450,  451,  450, 2915, 2915,  452, 2915,  450,  450, 2915,
+     2757, 2755, 2758, 2763, 2716,  450,  451, 2764, 2717,  450,
+      452, 2915, 2915,  450, 2915, 2915, 2915,  450, 2915,  450,
+     2761, 2775, 2775, 2915, 2782,  450, 2718,  450, 2783, 1216,
+
+     2719,  450,  450, 1217,  450,  450, 2915, 2915, 2915,  450,
+      450, 2720,  450, 2777, 2777, 2721, 2090,  450,  450, 2766,
+      450,  451,  450, 2915,  450,  452, 2915,  450, 2779, 2779,
+      450, 2915,  450, 2097, 2915,  450, 2915, 2098,  450,  450,
+      450, 2915, 2731,  450,  451, 2915, 2732,  450,  452,  450,
+     2915, 2915, 2915, 2915, 2915,  450, 2915,  450, 2785,  451,
+     2915,  450, 2915,  452,  451,  450, 2915, 2915,  452,  450,
+      450, 2915,  450, 2915, 2915, 2786, 2915,  450,  450,  451,
+      450, 2789, 2915,  452, 2790, 2915,  450,  450,  450,  451,
+     2915, 2915,  450,  452, 2915,  450, 2915, 2791,  451, 2915,
+
+      450,  451,  452,  450, 2792,  452, 2915,  450,  450, 2915,
+      451, 2915, 2915, 2915,  452,  450, 2801,  450, 2915, 2915,
+      451, 2915, 2915,  450,  452,  450,  450, 2793, 2915,  450,
+     2915, 2794, 2807,  450,  450, 2915, 2808,  450,  450, 2915,
+     2915, 2915,  450, 2915, 2915,  450,  450, 2915,  450, 2915,
+     2915, 2915, 2915, 2803,  450, 2915,  450, 2915, 2915, 2915,
+      450, 2805, 2915, 2915,  450, 2915, 2915, 2915,  450, 2915,
+     2915, 2915, 2915, 2915, 2809, 2915,  450, 2812, 2813, 2812,
+     2812, 2812, 2814, 2815, 2812, 2815, 2812, 2812, 2812, 2812,
+     2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2816,
+
+     2817, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812,
+     2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812,
+     2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812, 2812,
+     2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815,
+     2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2818,
+     2818, 2818, 2818, 2818, 2818, 2819, 2819, 2819, 2820, 2815,
+     2815,  451,  451, 2915, 2827,  452,  452, 2763, 2828, 2915,
+     2915, 2764, 2915,  451, 2915, 2915, 2915,  452, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,  450,
+      450, 2915,  450, 2824, 2915,  450, 2915,  450,  450, 2823,
+
+      450,  450, 2915,  450, 2915,  450,  450, 2915,  450,  450,
+      451,  450,  451, 2915,  452,  451,  452,  450, 2915,  452,
+     2915,  451, 2782, 2915, 2915,  452, 2783, 2775, 2775, 2777,
+     2777, 2915, 2779, 2779, 2915,  451, 2915, 2915,  450,  452,
+      450,  451, 2915,  450, 2090,  452,  450, 2915,  450,  450,
+      450,  450, 2836, 2915,  450, 2915,  450,  450,  450,  450,
+      451, 2915, 2915,  450,  452,  450,  450, 2915, 2915,  450,
+      451,  450,  451, 2915,  452, 2915,  452,  450, 2915,  450,
+     2915, 2915,  451,  451,  886,  450,  452,  452,  450,  451,
+     2915, 2915, 2915,  452, 2915,  959,  450, 2915,  450, 2915,
+
+      450,  451, 2915, 2915,  450,  452,  450, 1249,  450, 2915,
+      450,  450, 2915, 2915,  450, 2837,  450, 2846,  450,  450,
+     2848, 2915, 2915, 2915, 2849,  450, 2838,  450, 2839,  450,
+     2807,  451,  451,  450, 2808,  452,  452,  450, 2915, 2915,
+     2915, 2915,  451,  451, 2915,  450,  452,  452,  450, 2827,
+     2915, 2915, 2915, 2828, 2915, 2915,  450, 2915,  450,  450,
+      450, 2915, 2915, 2915,  450, 2915,  450,  450,  450,  451,
+      450,  450, 2915,  452,  450,  450,  450,  450,  450,  450,
+     2915, 2915, 2915, 2915, 2862,  450, 2854, 2855,  451, 2915,
+     2915,  451,  452,  450,  451,  452, 2915,  450,  452, 2915,
+
+     2915, 2915, 2915,  451, 2915,  450, 2848,  452, 2915, 2915,
+     2849, 2915, 2915,  450, 2915, 2915,  450, 2863, 2915,  450,
+     2915,  451,  450, 2864,  450,  452, 2915,  450, 2915, 2915,
+      450,  450,  450, 1585,  450,  450, 2868, 2915,  450,  450,
+      451,  451,  450, 2915,  452,  452, 2915,  450, 2915,  450,
+      450,  451,  451, 2915, 2915,  452,  452,  450, 2915, 2915,
+     2915, 2915,  451, 1430, 2915,  450,  452, 2915,  450,  450,
+     2915, 2915, 2915, 2915, 2915, 2915,  450,  450, 2870,  450,
+      450, 2915,  451, 2874,  450,  450,  452,  450,  450,  451,
+      450, 2915, 2875,  452, 2876,  450,  450, 2915,  450,  451,
+
+     2915, 2915, 2915,  452,  451, 2915, 2881, 2879,  452,  451,
+      450, 2915, 2915,  452, 2915, 2915,  451,  450,  450,  451,
+      452, 2915, 2885,  452, 2915,  450,  450,  450, 2915, 2887,
+     2915, 2915,  450,  450,  451,  450, 2890,  450,  452, 2915,
+      450, 2886, 2915,  450,  450,  450,  451,  450,  450, 2915,
+      452, 2915,  450,  450, 2915,  450, 2915,  451, 1981, 2895,
+      450,  452,  450,  450, 2915, 2915, 2915,  451, 2894,  451,
+      450,  452, 2915,  452,  450, 2915, 2915, 2915,  450,  451,
+     2915,  969,  450,  452, 2915,  450, 2915, 2915,  451, 2915,
+      450, 2915,  452,  450, 2915,  450,  923,  450, 2898, 2915,
+
+     2915,  450,  451,  450,  961,  450,  452,  450, 2915, 2915,
+     2915,  450, 2903,  450,  451,  450,  450,  451,  452, 2915,
+     2915,  452, 2915,  450,  450, 2915, 2915, 2915, 2915, 2915,
+      450, 2906,  450, 2915, 2915, 2909, 2915, 2915,  450, 2915,
+     2915, 2912,  450, 2915, 2915,  450,  450, 2915, 2915, 2915,
+      450, 2915, 2915,  450, 2915, 2915, 2915, 2915,  450,  958,
+     2915,  450,  124,  124,  124,  124,  124,  124,  124,  124,
+      124,  124,  124,  124,  124,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  169,  169,  257,  257,
+      257,  257,  257,  257,  257,  257,  257,  257,  257,  257,
+
+      257,  260,  260,  260,  260,  260,  260,  260,  260,  260,
+      260,  260,  260,  260,  282,  282,  282,  282,  282,  282,
+      282,  282,  282,  282,  282,  282,  282,  285,  285,  285,
+      285,  285,  285,  285,  285,  285,  285,  285,  285,  285,
+      290,  290,  290,  290,  290,  290,  290,  290,  290,  290,
+      290,  290,  290,  169,  169,  169,  169,  169,  169,  169,
+      169,  169,  169,  169,  169,  169,  316,  316,  316,  316,
+      316,  316,  316,  316,  316,  316,  316,  316,  316,  360,
+      360,  360,  360,  360,  360,  360,  360,  360,  360,  360,
+      360,  360,  363,  363,  363,  363,  363,  363,  363,  363,
+
+      363,  363,  363,  363,  363,  373,  373,  373,  373,  373,
+      373,  373,  373,  373,  373,  373,  373,  373,  382,  382,
+      382,  382,  382,  382,  382,  382,  382,  382,  382,  382,
+      382,  449,  449, 2915,  449,  449,  449,  449,  449,  449,
+      449,  449,  449,  449,  450,  450,  450,  450,  450, 2915,
+      450,  450,  450,  450,  550,  550, 2915,  550,  550,  550,
+      550,  550,  550,  550,  550,  550,  550,  551,  551, 2915,
+      551,  551,  551,  551,  551,  551,  551,  551,  551,  551,
+      552,  552,  552,  552,  552,  552,  552,  552,  552,  552,
+      557,  557, 2915,  557,  557,  557,  557,  557,  557,  557,
+
+      557,  557,  557,  558,  558, 2915,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  559,  559, 2915,  559,
+      559,  559,  559,  559,  559,  559,  559,  559,  559,  562,
+     2915,  562,  562, 2915,  562,  562,  562,  562,  562,  562,
+      562,  562,  570,  570, 2915, 2915,  570,  570,  570,  570,
+      570,  570,  574,  574, 2915,  574,  574,  574,  574,  574,
+      574,  574,  574,  574,  574,  575,  575, 2915,  575,  575,
+      575,  575,  575,  575,  575,  575,  575,  575,  576,  576,
+     2915, 2915,  576,  576,  576,  576,  576,  576,  580,  580,
+     2915,  580,  580,  580,  580,  580,  580,  580,  580,  580,
+
+      580,  581,  581, 2915,  581,  581,  581,  581,  581,  581,
+      581,  581,  581,  581,  583,  583,  583,  583,  583,  583,
+      583,  583, 2915,  583,  583,  583,  583,  588,  588, 2915,
+     2915,  588,  588,  588,  588,  588,  588,  592,  592,  592,
+      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
+      594,  594,  594,  594,  594,  594,  594,  594,  594,  594,
+      594,  594,  594,  596,  596, 2915, 2915,  596,  596,  596,
+      596,  596,  596,  600,  600, 2915,  600,  600,  600,  600,
+      600,  600,  600,  600,  600,  600,  601,  601, 2915,  601,
+      601,  601,  601,  601,  601,  601,  601,  601,  601,  602,
+
+      602, 2915, 2915,  602,  602,  602,  602,  602,  602,  606,
+      606, 2915,  606,  606,  606,  606,  606,  606,  606,  606,
+      606,  606,  607,  607, 2915,  607,  607,  607,  607,  607,
+      607,  607,  607,  607,  607,  608,  608, 2915, 2915,  608,
+      608,  608,  608,  608,  608,  612,  612, 2915,  612,  612,
+      612,  612,  612,  612,  612,  612,  612,  612,  613,  613,
+     2915,  613,  613,  613,  613,  613,  613,  613,  613,  613,
+      613,  614,  614, 2915, 2915,  614,  614,  614,  614,  614,
+      614,  618,  618, 2915,  618,  618,  618,  618,  618,  618,
+      618,  618,  618,  618,  619,  619, 2915,  619,  619,  619,
+
+      619,  619,  619,  619,  619,  619,  619,  620,  620, 2915,
+     2915,  620,  620,  620,  620,  620,  620,  624,  624, 2915,
+      624,  624,  624,  624,  624,  624,  624,  624,  624,  624,
+      625,  625, 2915,  625,  625,  625,  625,  625,  625,  625,
+      625,  625,  625,  626,  626, 2915, 2915,  626,  626,  626,
+      626,  626,  626,  630,  630, 2915,  630,  630,  630,  630,
+      630,  630,  630,  630,  630,  630,  631,  631, 2915,  631,
+      631,  631,  631,  631,  631,  631,  631,  631,  631,  632,
+      632, 2915, 2915,  632,  632,  632,  632,  632,  632,  636,
+      636, 2915,  636,  636,  636,  636,  636,  636,  636,  636,
+
+      636,  636,  637,  637, 2915,  637,  637,  637,  637,  637,
+      637,  637,  637,  637,  637,  638,  638, 2915, 2915,  638,
+      638,  638,  638,  638,  638,  642,  642, 2915,  642,  642,
+      642,  642,  642,  642,  642,  642,  642,  642,  643,  643,
+     2915,  643,  643,  643,  643,  643,  643,  643,  643,  643,
+      643,  644,  644, 2915, 2915,  644,  644,  644,  644,  644,
+      644,  648,  648, 2915,  648,  648,  648,  648,  648,  648,
+      648,  648,  648,  648,  649,  649, 2915,  649,  649,  649,
+      649,  649,  649,  649,  649,  649,  649,  650,  650, 2915,
+     2915,  650,  650,  650,  650,  650,  650,  654,  654, 2915,
+
+      654,  654,  654,  654,  654,  654,  654,  654,  654,  654,
+      655,  655, 2915,  655,  655,  655,  655,  655,  655,  655,
+      655,  655,  655,  656,  656, 2915, 2915,  656,  656,  656,
+      656,  656,  656,  660,  660, 2915,  660,  660,  660,  660,
+      660,  660,  660,  660,  660,  660,  661,  661, 2915,  661,
+      661,  661,  661,  661,  661,  661,  661,  661,  661,  662,
+      662,  662,  662, 2915,  662,  662,  662,  662,  662,  662,
+      662,  662,  663,  663, 2915,  663, 2915,  663,  663,  663,
+      663,  663,  663,  663,  663,  664,  664, 2915, 2915,  664,
+      664,  664,  664,  664,  664,  668,  668, 2915,  668,  668,
+
+      668,  668,  668,  668,  668,  668,  668,  668,  669,  669,
+     2915,  669,  669,  669,  669,  669,  669,  669,  669,  669,
+      669,  670,  670, 2915, 2915,  670,  670,  670,  670,  670,
+      670,  674,  674, 2915,  674,  674,  674,  674,  674,  674,
+      674,  674,  674,  674,  675,  675, 2915,  675,  675,  675,
+      675,  675,  675,  675,  675,  675,  675,  676,  676, 2915,
+     2915,  676,  676,  676,  676,  676,  676,  680,  680, 2915,
+      680,  680,  680,  680,  680,  680,  680,  680,  680,  680,
+      681,  681, 2915,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  682,  682, 2915, 2915,  682,  682,  682,
+
+      682,  682,  682,  686,  686, 2915,  686,  686,  686,  686,
+      686,  686,  686,  686,  686,  686,  687,  687, 2915,  687,
+      687,  687,  687,  687,  687,  687,  687,  687,  687,  688,
+      688,  688,  688,  688,  688, 2915,  688,  688,  688,  688,
+      688,  688,  689,  689, 2915, 2915,  689,  689,  689,  689,
+      689,  689,  693,  693, 2915,  693,  693,  693,  693,  693,
+      693,  693,  693,  693,  693,  694,  694, 2915,  694,  694,
+      694,  694,  694,  694,  694,  694,  694,  694,  695,  695,
+     2915, 2915,  695,  695,  695,  695,  695,  695,  699,  699,
+     2915,  699,  699,  699,  699,  699,  699,  699,  699,  699,
+
+      699,  700,  700, 2915,  700,  700,  700,  700,  700,  700,
+      700,  700,  700,  700,  701,  701, 2915, 2915,  701,  701,
+      701,  701,  701,  701,  705,  705, 2915,  705,  705,  705,
+      705,  705,  705,  705,  705,  705,  705,  706,  706, 2915,
+      706,  706,  706,  706,  706,  706,  706,  706,  706,  706,
+      707,  707, 2915, 2915,  707,  707,  707,  707,  707,  707,
+      711,  711, 2915,  711,  711,  711,  711,  711,  711,  711,
+      711,  711,  711,  712,  712, 2915,  712,  712,  712,  712,
+      712,  712,  712,  712,  712,  712,  713,  713,  713,  713,
+      713,  713,  713,  713,  713,  713,  713,  713,  713,  718,
+
+      718,  718,  718,  718,  718, 2915,  718,  718,  718,  718,
+      718,  718,  722,  722,  722,  722,  722,  722,  722,  722,
+      722,  722,  738,  738,  738,  738,  738,  738,  738,  738,
+      738, 2915,  738,  738,  738,  726,  726, 2915,  726,  726,
+      726,  726,  726,  726,  726,  726,  726,  726,  742,  742,
+     2915,  742,  742,  742,  742,  742,  742,  742,  742,  742,
+      742,  743,  743,  743,  743,  743,  743,  743,  743,  743,
+      743,  743, 2915,  743,  751,  751, 2915,  751,  751,  751,
+      751,  751,  751,  751,  751,  751,  751,  752,  752, 2915,
+      752,  752,  752,  752,  752,  752,  752,  752,  752,  752,
+
+      753,  753, 2915, 2915,  753,  753,  753,  753,  753,  753,
+      757,  757, 2915,  757,  757,  757,  757,  757,  757,  757,
+      757,  757,  757,  758,  758, 2915,  758,  758,  758,  758,
+      758,  758,  758,  758,  758,  758,  759,  759, 2915, 2915,
+      759,  759,  759,  759,  759,  759,  763,  763, 2915,  763,
+      763,  763,  763,  763,  763,  763,  763,  763,  763,  764,
+      764, 2915,  764,  764,  764,  764,  764,  764,  764,  764,
+      764,  764,  765,  765, 2915, 2915,  765,  765,  765,  765,
+      765,  765,  769,  769, 2915,  769,  769,  769,  769,  769,
+      769,  769,  769,  769,  769,  770,  770, 2915,  770,  770,
+
+      770,  770,  770,  770,  770,  770,  770,  770,  771,  771,
+     2915, 2915,  771,  771,  771,  771,  771,  771,  775,  775,
+     2915,  775,  775,  775,  775,  775,  775,  775,  775,  775,
+      775,  776,  776, 2915,  776,  776,  776,  776,  776,  776,
+      776,  776,  776,  776,  777, 2915,  777,  777, 2915,  777,
+      777,  777,  777,  777,  777,  777,  777,  778, 2915,  778,
+      778, 2915,  778,  778,  778, 2915,  778,  778,  778,  778,
+      779,  779, 2915, 2915,  779,  779,  779,  779,  779,  779,
+      783,  783, 2915,  783,  783,  783,  783,  783,  783,  783,
+      783,  783,  783,  784,  784, 2915,  784,  784,  784,  784,
+
+      784,  784,  784,  784,  784,  784,  785, 2915,  785,  785,
+     2915,  785,  785,  785,  785,  785,  785,  785,  785,  787,
+      787, 2915, 2915,  787,  787,  787,  787,  787,  787,  791,
+      791, 2915,  791,  791,  791,  791,  791,  791,  791,  791,
+      791,  791,  792,  792, 2915,  792,  792,  792,  792,  792,
+      792,  792,  792,  792,  792,  793, 2915,  793,  793, 2915,
+      793,  793,  793,  793,  793,  793,  793,  793,  795,  795,
+     2915, 2915,  795,  795,  795,  795,  795,  795,  799,  799,
+     2915,  799,  799,  799,  799,  799,  799,  799,  799,  799,
+      799,  800,  800, 2915,  800,  800,  800,  800,  800,  800,
+
+      800,  800,  800,  800,  801,  801, 2915, 2915,  801,  801,
+      801,  801,  801,  801,  805,  805, 2915,  805,  805,  805,
+      805,  805,  805,  805,  805,  805,  805,  806,  806, 2915,
+      806,  806,  806,  806,  806,  806,  806,  806,  806,  806,
+      807,  807, 2915, 2915,  807,  807,  807,  807,  807,  807,
+      811,  811, 2915,  811,  811,  811,  811,  811,  811,  811,
+      811,  811,  811,  812,  812, 2915,  812,  812,  812,  812,
+      812,  812,  812,  812,  812,  812,  813,  813, 2915,  813,
+      813,  813,  813,  813,  813,  813,  813,  813,  813,  814,
+      814, 2915,  814,  814,  814,  814,  814,  814,  814,  814,
+
+      814,  814,  815,  815, 2915,  815,  815,  815,  815,  815,
+      815,  815,  815,  815,  815,  817,  817, 2915, 2915,  817,
+      817,  817,  817,  817,  817,  821,  821, 2915,  821,  821,
+      821,  821,  821,  821,  821,  821,  821,  821,  822,  822,
+     2915,  822,  822,  822,  822,  822,  822,  822,  822,  822,
+      822,  823,  823, 2915, 2915,  823,  823,  823,  823,  823,
+      823,  827,  827, 2915,  827,  827,  827,  827,  827,  827,
+      827,  827,  827,  827,  828,  828, 2915,  828,  828,  828,
+      828,  828,  828,  828,  828,  828,  828,  829,  829, 2915,
+     2915,  829,  829,  829,  829,  829,  829,  833,  833, 2915,
+
+      833,  833,  833,  833,  833,  833,  833,  833,  833,  833,
+      834,  834, 2915,  834,  834,  834,  834,  834,  834,  834,
+      834,  834,  834,  835,  835, 2915,  835,  835,  835,  835,
+      835,  835,  835,  835,  835,  835,  836,  836, 2915,  836,
+      836,  836,  836,  836,  836,  836,  836,  836,  836,  837,
+      837, 2915,  837,  837,  837,  837,  837,  837,  837,  837,
+      837,  837,  838,  838, 2915, 2915,  838,  838,  838,  838,
+      838,  838,  842,  842, 2915,  842,  842,  842,  842,  842,
+      842,  842,  842,  842,  842,  843,  843, 2915,  843,  843,
+      843,  843,  843,  843,  843,  843,  843,  843,  844,  844,
+
+     2915, 2915,  844,  844,  844,  844,  844,  844,  848,  848,
+     2915,  848,  848,  848,  848,  848,  848,  848,  848,  848,
+      848,  849,  849, 2915,  849,  849,  849,  849,  849,  849,
+      849,  849,  849,  849,  850,  850, 2915, 2915,  850,  850,
+      850,  850,  850,  850,  854,  854, 2915,  854,  854,  854,
+      854,  854,  854,  854,  854,  854,  854,  855,  855, 2915,
+      855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
+      856,  856, 2915, 2915,  856,  856,  856,  856,  856,  856,
+      860,  860, 2915,  860,  860,  860,  860,  860,  860,  860,
+      860,  860,  860,  861,  861, 2915,  861,  861,  861,  861,
+
+      861,  861,  861,  861,  861,  861,  449,  449, 2915,  449,
+      449,  449,  449,  449,  449,  449,  449,  449,  449,  450,
+      450,  450,  450,  450, 2915,  450,  450,  450,  450,  550,
+      550, 2915,  550,  550,  550,  550,  550,  550,  550,  550,
+      550,  550,  551,  551, 2915,  551,  551,  551,  551,  551,
+      551,  551,  551,  551,  551,  994,  994, 2915,  994,  994,
+      994,  994,  994,  994,  994,  994,  994,  994,  552,  552,
+     2915,  552,  552,  552,  552,  552,  552,  552,  552,  552,
+      552,  995,  995, 2915,  995,  995,  995,  995,  995,  995,
+      995,  995,  995,  995,  996,  996, 2915,  996,  996,  996,
+
+      996,  996,  996,  996,  996,  996,  996,  557,  557, 2915,
+      557,  557,  557,  557,  557,  557,  557,  557,  557,  557,
+      997,  997, 2915,  997,  997,  997,  997,  997,  997,  997,
+      997,  997,  997,  562, 2915,  562,  562, 2915,  562,  562,
+      562,  562,  562,  562,  562,  562,  570,  570, 2915, 2915,
+      570,  570,  570,  570,  570,  570,  574,  574, 2915,  574,
+      574,  574,  574,  574,  574,  574,  574,  574,  574,  575,
+      575, 2915,  575,  575,  575,  575,  575,  575,  575,  575,
+      575,  575, 1000, 1000, 2915, 1000, 1000, 1000, 1000, 1000,
+     1000, 1000, 1000, 1000, 1000,  576,  576, 2915, 2915,  576,
+
+      576,  576,  576,  576,  576,  580,  580, 2915,  580,  580,
+      580,  580,  580,  580,  580,  580,  580,  580,  581,  581,
+     2915,  581,  581,  581,  581,  581,  581,  581,  581,  581,
+      581, 1001, 1001, 2915, 1001, 1001, 1001, 1001, 1001, 1001,
+     1001, 1001, 1001, 1001,  583,  583,  583,  583,  583,  583,
+      583,  583, 2915,  583,  583,  583,  583,  588,  588, 2915,
+     2915,  588,  588,  588,  588,  588,  588,  592,  592,  592,
+      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
+      594,  594,  594,  594,  594,  594,  594,  594,  594,  594,
+      594,  594,  594,  593,  593, 2915,  593,  593,  593,  593,
+
+      593,  593,  593,  593,  593,  593,  595,  595, 2915,  595,
+      595,  595,  595,  595,  595,  595,  595,  595,  595, 1002,
+     1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002,
+     1002, 1002, 1003, 1003, 2915, 1003, 1003, 1003, 1003, 1003,
+     1003, 1003, 1003, 1003, 1003,  596,  596, 2915, 2915,  596,
+      596,  596,  596,  596,  596,  600,  600, 2915,  600,  600,
+      600,  600,  600,  600,  600,  600,  600,  600,  601,  601,
+     2915,  601,  601,  601,  601,  601,  601,  601,  601,  601,
+      601, 1004, 1004, 2915, 1004, 1004, 1004, 1004, 1004, 1004,
+     1004, 1004, 1004, 1004,  602,  602, 2915, 2915,  602,  602,
+
+      602,  602,  602,  602,  606,  606, 2915,  606,  606,  606,
+      606,  606,  606,  606,  606,  606,  606,  607,  607, 2915,
+      607,  607,  607,  607,  607,  607,  607,  607,  607,  607,
+     1005, 1005, 2915, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
+     1005, 1005, 1005,  608,  608, 2915, 2915,  608,  608,  608,
+      608,  608,  608,  612,  612, 2915,  612,  612,  612,  612,
+      612,  612,  612,  612,  612,  612,  613,  613, 2915,  613,
+      613,  613,  613,  613,  613,  613,  613,  613,  613, 1006,
+     1006, 2915, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006,
+     1006, 1006,  614,  614, 2915, 2915,  614,  614,  614,  614,
+
+      614,  614,  618,  618, 2915,  618,  618,  618,  618,  618,
+      618,  618,  618,  618,  618,  619,  619, 2915,  619,  619,
+      619,  619,  619,  619,  619,  619,  619,  619, 1007, 1007,
+     2915, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007,
+     1007,  620,  620, 2915, 2915,  620,  620,  620,  620,  620,
+      620,  624,  624, 2915,  624,  624,  624,  624,  624,  624,
+      624,  624,  624,  624,  625,  625, 2915,  625,  625,  625,
+      625,  625,  625,  625,  625,  625,  625, 1008, 1008, 2915,
+     1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008,
+      626,  626, 2915, 2915,  626,  626,  626,  626,  626,  626,
+
+      630,  630, 2915,  630,  630,  630,  630,  630,  630,  630,
+      630,  630,  630,  631,  631, 2915,  631,  631,  631,  631,
+      631,  631,  631,  631,  631,  631, 1009, 1009, 2915, 1009,
+     1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009,  632,
+      632, 2915, 2915,  632,  632,  632,  632,  632,  632,  636,
+      636, 2915,  636,  636,  636,  636,  636,  636,  636,  636,
+      636,  636,  637,  637, 2915,  637,  637,  637,  637,  637,
+      637,  637,  637,  637,  637, 1010, 1010, 2915, 1010, 1010,
+     1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010,  638,  638,
+     2915, 2915,  638,  638,  638,  638,  638,  638,  642,  642,
+
+     2915,  642,  642,  642,  642,  642,  642,  642,  642,  642,
+      642,  643,  643, 2915,  643,  643,  643,  643,  643,  643,
+      643,  643,  643,  643, 1011, 1011, 2915, 1011, 1011, 1011,
+     1011, 1011, 1011, 1011, 1011, 1011, 1011,  644,  644, 2915,
+     2915,  644,  644,  644,  644,  644,  644,  648,  648, 2915,
+      648,  648,  648,  648,  648,  648,  648,  648,  648,  648,
+      649,  649, 2915,  649,  649,  649,  649,  649,  649,  649,
+      649,  649,  649, 1012, 1012, 2915, 1012, 1012, 1012, 1012,
+     1012, 1012, 1012, 1012, 1012, 1012,  650,  650, 2915, 2915,
+      650,  650,  650,  650,  650,  650,  654,  654, 2915,  654,
+
+      654,  654,  654,  654,  654,  654,  654,  654,  654,  655,
+      655, 2915,  655,  655,  655,  655,  655,  655,  655,  655,
+      655,  655, 1013, 1013, 2915, 1013, 1013, 1013, 1013, 1013,
+     1013, 1013, 1013, 1013, 1013,  656,  656, 2915, 2915,  656,
+      656,  656,  656,  656,  656,  660,  660, 2915,  660,  660,
+      660,  660,  660,  660,  660,  660,  660,  660,  661,  661,
+     2915,  661,  661,  661,  661,  661,  661,  661,  661,  661,
+      661, 1014, 1014, 2915, 1014, 1014, 1014, 1014, 1014, 1014,
+     1014, 1014, 1014, 1014,  662,  662,  662,  662, 2915,  662,
+      662,  662,  662,  662,  662,  662,  662,  663,  663, 2915,
+
+      663, 2915,  663,  663,  663,  663,  663,  663,  663,  663,
+      664,  664, 2915, 2915,  664,  664,  664,  664,  664,  664,
+      668,  668, 2915,  668,  668,  668,  668,  668,  668,  668,
+      668,  668,  668,  669,  669, 2915,  669,  669,  669,  669,
+      669,  669,  669,  669,  669,  669, 1015, 1015, 2915, 1015,
+     1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015,  670,
+      670, 2915, 2915,  670,  670,  670,  670,  670,  670,  674,
+      674, 2915,  674,  674,  674,  674,  674,  674,  674,  674,
+      674,  674,  675,  675, 2915,  675,  675,  675,  675,  675,
+      675,  675,  675,  675,  675, 1016, 1016, 2915, 1016, 1016,
+
+     1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016,  676,  676,
+     2915, 2915,  676,  676,  676,  676,  676,  676,  680,  680,
+     2915,  680,  680,  680,  680,  680,  680,  680,  680,  680,
+      680,  681,  681, 2915,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681, 1017, 1017, 2915, 1017, 1017, 1017,
+     1017, 1017, 1017, 1017, 1017, 1017, 1017,  682,  682, 2915,
+     2915,  682,  682,  682,  682,  682,  682,  686,  686, 2915,
+      686,  686,  686,  686,  686,  686,  686,  686,  686,  686,
+      687,  687, 2915,  687,  687,  687,  687,  687,  687,  687,
+      687,  687,  687, 1018, 1018, 2915, 1018, 1018, 1018, 1018,
+
+     1018, 1018, 1018, 1018, 1018, 1018,  688,  688,  688,  688,
+      688,  688, 2915,  688,  688,  688,  688,  688,  688,  689,
+      689, 2915, 2915,  689,  689,  689,  689,  689,  689,  693,
+      693, 2915,  693,  693,  693,  693,  693,  693,  693,  693,
+      693,  693,  694,  694, 2915,  694,  694,  694,  694,  694,
+      694,  694,  694,  694,  694, 1019, 1019, 2915, 1019, 1019,
+     1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019,  695,  695,
+     2915, 2915,  695,  695,  695,  695,  695,  695,  699,  699,
+     2915,  699,  699,  699,  699,  699,  699,  699,  699,  699,
+      699,  700,  700, 2915,  700,  700,  700,  700,  700,  700,
+
+      700,  700,  700,  700, 1020, 1020, 2915, 1020, 1020, 1020,
+     1020, 1020, 1020, 1020, 1020, 1020, 1020,  701,  701, 2915,
+     2915,  701,  701,  701,  701,  701,  701,  705,  705, 2915,
+      705,  705,  705,  705,  705,  705,  705,  705,  705,  705,
+      706,  706, 2915,  706,  706,  706,  706,  706,  706,  706,
+      706,  706,  706, 1021, 1021, 2915, 1021, 1021, 1021, 1021,
+     1021, 1021, 1021, 1021, 1021, 1021,  707,  707, 2915, 2915,
+      707,  707,  707,  707,  707,  707,  711,  711, 2915,  711,
+      711,  711,  711,  711,  711,  711,  711,  711,  711,  712,
+      712, 2915,  712,  712,  712,  712,  712,  712,  712,  712,
+
+      712,  712, 1022, 1022, 2915, 1022, 1022, 1022, 1022, 1022,
+     1022, 1022, 1022, 1022, 1022,  713,  713,  713,  713,  713,
+      713,  713,  713,  713,  713,  713,  713,  713,  718,  718,
+      718,  718,  718,  718,  718,  718,  718,  718,  718,  718,
+      718, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
+     1024, 1024, 1024, 1024, 1029, 1029, 1029, 1029, 1029, 1029,
+     1029, 1029, 1029, 1029, 1029, 1029, 1029, 1034, 1034, 1034,
+     1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034,
+      722,  722, 2915,  722,  722,  722,  722,  722,  722,  722,
+      722,  722,  722, 1039, 1039, 2915, 1039, 1039, 1039, 1039,
+
+     1039, 1039, 1039, 1039, 1039, 1039, 1040, 1040, 2915, 1040,
+     1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040,  726,
+      726, 2915,  726,  726,  726,  726,  726,  726,  726,  726,
+      726,  726,  742,  742, 2915,  742,  742,  742,  742,  742,
+      742,  742,  742,  742,  742,  743,  743,  743,  743,  743,
+      743,  743,  743,  743,  743,  743, 2915,  743,  751,  751,
+     2915,  751,  751,  751,  751,  751,  751,  751,  751,  751,
+      751,  752,  752, 2915,  752,  752,  752,  752,  752,  752,
+      752,  752,  752,  752,  738,  738,  738,  738,  738,  738,
+      738,  738,  738,  738,  738,  738,  738, 1043, 1043, 1043,
+
+     1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043,
+     1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048,
+     1048, 1048, 1048, 1053, 1053, 1053, 1053, 1053, 1053, 1053,
+     1053, 1053, 1053, 1053, 1053, 1053, 1058, 1058, 1058, 1058,
+     1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1059,
+     1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059,
+     1059, 1059, 1060, 1060, 2915, 1060, 1060, 1060, 1060, 1060,
+     1060, 1060, 1060, 1060, 1060,  753,  753, 2915, 2915,  753,
+      753,  753,  753,  753,  753,  757,  757, 2915,  757,  757,
+      757,  757,  757,  757,  757,  757,  757,  757,  758,  758,
+
+     2915,  758,  758,  758,  758,  758,  758,  758,  758,  758,
+      758, 1061, 1061, 2915, 1061, 1061, 1061, 1061, 1061, 1061,
+     1061, 1061, 1061, 1061,  759,  759, 2915, 2915,  759,  759,
+      759,  759,  759,  759,  763,  763, 2915,  763,  763,  763,
+      763,  763,  763,  763,  763,  763,  763,  764,  764, 2915,
+      764,  764,  764,  764,  764,  764,  764,  764,  764,  764,
+     1062, 1062, 2915, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
+     1062, 1062, 1062,  765,  765, 2915, 2915,  765,  765,  765,
+      765,  765,  765,  769,  769, 2915,  769,  769,  769,  769,
+      769,  769,  769,  769,  769,  769,  770,  770, 2915,  770,
+
+      770,  770,  770,  770,  770,  770,  770,  770,  770, 1063,
+     1063, 2915, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+     1063, 1063,  771,  771, 2915, 2915,  771,  771,  771,  771,
+      771,  771,  775,  775, 2915,  775,  775,  775,  775,  775,
+      775,  775,  775,  775,  775,  776,  776, 2915,  776,  776,
+      776,  776,  776,  776,  776,  776,  776,  776, 1064, 1064,
+     2915, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064,
+     1064,  777, 2915,  777,  777, 2915,  777,  777,  777,  777,
+      777,  777,  777,  777,  778, 2915,  778,  778, 2915,  778,
+      778,  778, 2915,  778,  778,  778,  778,  779,  779, 2915,
+
+     2915,  779,  779,  779,  779,  779,  779,  783,  783, 2915,
+      783,  783,  783,  783,  783,  783,  783,  783,  783,  783,
+      784,  784, 2915,  784,  784,  784,  784,  784,  784,  784,
+      784,  784,  784, 1065, 1065, 2915, 1065, 1065, 1065, 1065,
+     1065, 1065, 1065, 1065, 1065, 1065,  785, 2915,  785,  785,
+     2915,  785,  785,  785,  785,  785,  785,  785,  785,  787,
+      787, 2915, 2915,  787,  787,  787,  787,  787,  787,  791,
+      791, 2915,  791,  791,  791,  791,  791,  791,  791,  791,
+      791,  791,  792,  792, 2915,  792,  792,  792,  792,  792,
+      792,  792,  792,  792,  792, 1067, 1067, 2915, 1067, 1067,
+
+     1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067,  793, 2915,
+      793,  793, 2915,  793,  793,  793,  793,  793,  793,  793,
+      793,  795,  795, 2915, 2915,  795,  795,  795,  795,  795,
+      795,  799,  799, 2915,  799,  799,  799,  799,  799,  799,
+      799,  799,  799,  799,  800,  800, 2915,  800,  800,  800,
+      800,  800,  800,  800,  800,  800,  800, 1069, 1069, 2915,
+     1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069,
+      801,  801, 2915, 2915,  801,  801,  801,  801,  801,  801,
+      805,  805, 2915,  805,  805,  805,  805,  805,  805,  805,
+      805,  805,  805,  806,  806, 2915,  806,  806,  806,  806,
+
+      806,  806,  806,  806,  806,  806, 1070, 1070, 2915, 1070,
+     1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070,  807,
+      807, 2915, 2915,  807,  807,  807,  807,  807,  807,  811,
+      811, 2915,  811,  811,  811,  811,  811,  811,  811,  811,
+      811,  811,  812,  812, 2915,  812,  812,  812,  812,  812,
+      812,  812,  812,  812,  812, 1071, 1071, 2915, 1071, 1071,
+     1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071,  813,  813,
+     2915,  813,  813,  813,  813,  813,  813,  813,  813,  813,
+      813, 1072, 1072, 2915, 1072, 1072, 1072, 1072, 1072, 1072,
+     1072, 1072, 1072, 1072,  817,  817, 2915, 2915,  817,  817,
+
+      817,  817,  817,  817,  821,  821, 2915,  821,  821,  821,
+      821,  821,  821,  821,  821,  821,  821,  822,  822, 2915,
+      822,  822,  822,  822,  822,  822,  822,  822,  822,  822,
+     1073, 1073, 2915, 1073, 1073, 1073, 1073, 1073, 1073, 1073,
+     1073, 1073, 1073,  823,  823, 2915, 2915,  823,  823,  823,
+      823,  823,  823,  827,  827, 2915,  827,  827,  827,  827,
+      827,  827,  827,  827,  827,  827,  828,  828, 2915,  828,
+      828,  828,  828,  828,  828,  828,  828,  828,  828, 1074,
+     1074, 2915, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074,
+     1074, 1074,  829,  829, 2915, 2915,  829,  829,  829,  829,
+
+      829,  829,  833,  833, 2915,  833,  833,  833,  833,  833,
+      833,  833,  833,  833,  833,  834,  834, 2915,  834,  834,
+      834,  834,  834,  834,  834,  834,  834,  834, 1075, 1075,
+     2915, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075,
+     1075,  835,  835, 2915,  835,  835,  835,  835,  835,  835,
+      835,  835,  835,  835, 1076, 1076, 2915, 1076, 1076, 1076,
+     1076, 1076, 1076, 1076, 1076, 1076, 1076,  838,  838, 2915,
+     2915,  838,  838,  838,  838,  838,  838,  842,  842, 2915,
+      842,  842,  842,  842,  842,  842,  842,  842,  842,  842,
+      843,  843, 2915,  843,  843,  843,  843,  843,  843,  843,
+
+      843,  843,  843, 1077, 1077, 2915, 1077, 1077, 1077, 1077,
+     1077, 1077, 1077, 1077, 1077, 1077,  844,  844, 2915, 2915,
+      844,  844,  844,  844,  844,  844,  848,  848, 2915,  848,
+      848,  848,  848,  848,  848,  848,  848,  848,  848,  849,
+      849, 2915,  849,  849,  849,  849,  849,  849,  849,  849,
+      849,  849, 1078, 1078, 2915, 1078, 1078, 1078, 1078, 1078,
+     1078, 1078, 1078, 1078, 1078,  850,  850, 2915, 2915,  850,
+      850,  850,  850,  850,  850,  854,  854, 2915,  854,  854,
+      854,  854,  854,  854,  854,  854,  854,  854,  855,  855,
+     2915,  855,  855,  855,  855,  855,  855,  855,  855,  855,
+
+      855, 1079, 1079, 2915, 1079, 1079, 1079, 1079, 1079, 1079,
+     1079, 1079, 1079, 1079,  856,  856, 2915, 2915,  856,  856,
+      856,  856,  856,  856,  860,  860, 2915,  860,  860,  860,
+      860,  860,  860,  860,  860,  860,  860,  861,  861, 2915,
+      861,  861,  861,  861,  861,  861,  861,  861,  861,  861,
+     1080, 1080, 2915, 1080, 1080, 1080, 1080, 1080, 1080, 1080,
+     1080, 1080, 1080,  450,  450,  450,  450,  450, 2915,  450,
+      450,  450,  450,  976,  976,  976,  976,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  550,  550, 2915,  550,
+      550,  550,  550,  550,  550,  550,  550,  550,  550,  551,
+
+      551, 2915,  551,  551,  551,  551,  551,  551,  551,  551,
+      551,  551,  552,  552, 2915,  552,  552,  552,  552,  552,
+      552,  552,  552,  552,  552, 1281, 1281, 2915, 1281, 1281,
+     1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,  557,  557,
+     2915,  557,  557,  557,  557,  557,  557,  557,  557,  557,
+      557,  562, 2915,  562,  562, 2915,  562,  562,  562,  562,
+      562,  562,  562,  562,  570,  570, 2915,  570,  570,  570,
+      570,  570,  570,  570,  570,  570,  570,  576,  576, 2915,
+      576,  576,  576,  576,  576,  576,  576,  576,  576,  576,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+
+      582,  582,  582,  588,  588, 2915,  588,  588,  588,  588,
+      588,  588,  588,  588,  588,  588,  596,  596, 2915,  596,
+      596,  596,  596,  596,  596,  596,  596,  596,  596,  602,
+      602, 2915,  602,  602,  602,  602,  602,  602,  602,  602,
+      602,  602,  608,  608, 2915,  608,  608,  608,  608,  608,
+      608,  608,  608,  608,  608,  614,  614, 2915,  614,  614,
+      614,  614,  614,  614,  614,  614,  614,  614,  620,  620,
+     2915,  620,  620,  620,  620,  620,  620,  620,  620,  620,
+      620,  626,  626, 2915,  626,  626,  626,  626,  626,  626,
+      626,  626,  626,  626,  632,  632, 2915,  632,  632,  632,
+
+      632,  632,  632,  632,  632,  632,  632,  638,  638, 2915,
+      638,  638,  638,  638,  638,  638,  638,  638,  638,  638,
+      644,  644, 2915,  644,  644,  644,  644,  644,  644,  644,
+      644,  644,  644,  650,  650, 2915,  650,  650,  650,  650,
+      650,  650,  650,  650,  650,  650,  656,  656, 2915,  656,
+      656,  656,  656,  656,  656,  656,  656,  656,  656,  664,
+      664, 2915,  664,  664,  664,  664,  664,  664,  664,  664,
+      664,  664,  670,  670, 2915,  670,  670,  670,  670,  670,
+      670,  670,  670,  670,  670,  676,  676, 2915,  676,  676,
+      676,  676,  676,  676,  676,  676,  676,  676,  682,  682,
+
+     2915,  682,  682,  682,  682,  682,  682,  682,  682,  682,
+      682,  689,  689, 2915,  689,  689,  689,  689,  689,  689,
+      689,  689,  689,  689,  695,  695, 2915,  695,  695,  695,
+      695,  695,  695,  695,  695,  695,  695,  701,  701, 2915,
+      701,  701,  701,  701,  701,  701,  701,  701,  701,  701,
+      707,  707, 2915,  707,  707,  707,  707,  707,  707,  707,
+      707,  707,  707,  718,  718,  718,  718,  718,  718,  718,
+      718,  718,  718,  718,  718,  718, 1024, 1024, 1024, 1024,
+     1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1029,
+     1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029,
+
+     1029, 1029, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034,
+     1034, 1034, 1034, 1034, 1034, 1282, 1282, 1282, 1282, 1282,
+     1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1287, 1287,
+     1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
+     1287, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
+     1292, 1292, 1292, 1292, 1297, 1297, 1297, 1297, 1297, 1297,
+     1297, 1297, 1297, 1297, 1297, 1297, 1297, 1302, 1302, 2915,
+     1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302,
+     1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303,
+     1303, 1303, 1303, 1308, 1308, 1308, 1308, 1308, 1308, 1308,
+
+     1308, 1308, 1308, 1308, 1308, 1308, 1313, 1313, 1313, 1313,
+     1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313,  722,
+      722, 2915,  722,  722,  722,  722,  722,  722,  722,  722,
+      722,  722, 1318, 1318, 2915, 1318, 1318, 1318, 1318, 1318,
+     1318, 1318, 1318, 1318, 1318,  738,  738,  738,  738,  738,
+      738,  738,  738,  738,  738,  738,  738,  738, 1043, 1043,
+     1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043,
+     1043, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048,
+     1048, 1048, 1048, 1048, 1053, 1053, 1053, 1053, 1053, 1053,
+     1053, 1053, 1053, 1053, 1053, 1053, 1053, 1319, 1319, 1319,
+
+     1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319,
+     1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324,
+     1324, 1324, 1324, 1329, 1329, 1329, 1329, 1329, 1329, 1329,
+     1329, 1329, 1329, 1329, 1329, 1329, 1334, 1334, 1334, 1334,
+     1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1339,
+     1339, 2915, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339,
+     1339, 1339, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340,
+     1340, 1340, 1340, 1340, 1340, 1345, 1345, 1345, 1345, 1345,
+     1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1350, 1350,
+     1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350,
+
+     1350,  726,  726, 2915,  726,  726,  726,  726,  726,  726,
+      726,  726,  726,  726,  753,  753, 2915,  753,  753,  753,
+      753,  753,  753,  753,  753,  753,  753,  759,  759, 2915,
+      759,  759,  759,  759,  759,  759,  759,  759,  759,  759,
+      765,  765, 2915,  765,  765,  765,  765,  765,  765,  765,
+      765,  765,  765,  771,  771, 2915,  771,  771,  771,  771,
+      771,  771,  771,  771,  771,  771,  779,  779, 2915,  779,
+      779,  779,  779,  779,  779,  779,  779,  779,  779,  787,
+      787, 2915,  787,  787,  787,  787,  787,  787,  787,  787,
+      787,  787,  795,  795, 2915,  795,  795,  795,  795,  795,
+
+      795,  795,  795,  795,  795,  801,  801, 2915,  801,  801,
+      801,  801,  801,  801,  801,  801,  801,  801,  807,  807,
+     2915,  807,  807,  807,  807,  807,  807,  807,  807,  807,
+      807,  813,  813, 2915,  813,  813,  813,  813,  813,  813,
+      813,  813,  813,  813,  817,  817, 2915,  817,  817,  817,
+      817,  817,  817,  817,  817,  817,  817,  823,  823, 2915,
+      823,  823,  823,  823,  823,  823,  823,  823,  823,  823,
+      829,  829, 2915,  829,  829,  829,  829,  829,  829,  829,
+      829,  829,  829,  835,  835, 2915,  835,  835,  835,  835,
+      835,  835,  835,  835,  835,  835,  838,  838, 2915,  838,
+
+      838,  838,  838,  838,  838,  838,  838,  838,  838,  844,
+      844, 2915,  844,  844,  844,  844,  844,  844,  844,  844,
+      844,  844,  850,  850, 2915,  850,  850,  850,  850,  850,
+      850,  850,  850,  850,  850,  856,  856, 2915,  856,  856,
+      856,  856,  856,  856,  856,  856,  856,  856,  450,  450,
+      450,  450,  450, 2915,  450,  450,  450,  450, 1362, 1362,
+     1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362,
+     1362, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 1373, 1373, 1373, 1403, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1403, 1403, 1403, 1403, 1403, 1135, 1135, 1135,
+
+     1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135,
+      550,  550, 2915,  550,  550,  550,  550,  550,  550,  550,
+      550,  550,  550,  551,  551, 2915,  551,  551,  551,  551,
+      551,  551,  551,  551,  551,  551, 1467, 1467, 1467, 1467,
+     1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1550,
+     1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550,
+     1550, 1550, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,
+     1607, 1607, 1607, 1607, 1607,  552,  552, 2915,  552,  552,
+      552,  552,  552,  552,  552,  552,  552,  552,  718,  718,
+      718,  718,  718,  718,  718,  718,  718,  718,  718,  718,
+
+      718, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
+     1024, 1024, 1024, 1024, 1029, 1029, 1029, 1029, 1029, 1029,
+     1029, 1029, 1029, 1029, 1029, 1029, 1029, 1034, 1034, 1034,
+     1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034,
+     1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282,
+     1282, 1282, 1282, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
+     1287, 1287, 1287, 1287, 1287, 1287, 1292, 1292, 1292, 1292,
+     1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1297,
+     1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
+     1297, 1297, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303,
+
+     1303, 1303, 1303, 1303, 1303, 1308, 1308, 1308, 1308, 1308,
+     1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1313, 1313,
+     1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313,
+     1313, 1623, 1623, 1623, 1623, 1623, 1623, 1623, 1623, 1623,
+     1623, 1623, 1623, 1623, 1628, 1628, 1628, 1628, 1628, 1628,
+     1628, 1628, 1628, 1628, 1628, 1628, 1628, 1633, 1633, 1633,
+     1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633,
+     1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638,
+     1638, 1638, 1638, 1643, 1643, 1643, 1643, 1643, 1643, 1643,
+     1643, 1643, 1643, 1643, 1643, 1643, 1648, 1648, 1648, 1648,
+
+     1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,  722,
+      722, 2915,  722,  722,  722,  722,  722,  722,  722,  722,
+      722,  722,  738,  738,  738,  738,  738,  738,  738,  738,
+      738,  738,  738,  738,  738, 1043, 1043, 1043, 1043, 1043,
+     1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1048, 1048,
+     1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048,
+     1048, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053,
+     1053, 1053, 1053, 1053, 1319, 1319, 1319, 1319, 1319, 1319,
+     1319, 1319, 1319, 1319, 1319, 1319, 1319, 1324, 1324, 1324,
+     1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324,
+
+     1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329,
+     1329, 1329, 1329, 1334, 1334, 1334, 1334, 1334, 1334, 1334,
+     1334, 1334, 1334, 1334, 1334, 1334, 1340, 1340, 1340, 1340,
+     1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1345,
+     1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345,
+     1345, 1345, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350,
+     1350, 1350, 1350, 1350, 1350, 1653, 1653, 1653, 1653, 1653,
+     1653, 1653, 1653, 1653, 1653, 1653, 1653, 1653, 1658, 1658,
+     1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+     1658, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663,
+
+     1663, 1663, 1663, 1663, 1668, 1668, 1668, 1668, 1668, 1668,
+     1668, 1668, 1668, 1668, 1668, 1668, 1668, 1673, 1673, 1673,
+     1673, 1673, 1673, 1673, 1673, 1673, 1673, 1673, 1673, 1673,
+     1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678,
+     1678, 1678, 1678,  450,  450,  450,  450,  450, 2915,  450,
+      450,  450,  450,  550,  550, 2915,  550,  550,  550,  550,
+      550,  550,  550,  550,  550,  550,  551,  551, 2915,  551,
+      551,  551,  551,  551,  551,  551,  551,  551,  551, 1362,
+     1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362,
+     1362, 1362, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+
+     1373, 1373, 1373, 1373, 1373, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1413, 1413,
+     1413, 1413, 1413, 1413, 1413, 1413, 2915, 1413, 1413, 1413,
+     1413, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421,
+     1421, 1421, 1421, 1421, 1734, 1734, 1734, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1734, 1476, 1476, 1476,
+     1476, 1476, 1476, 1476, 1476, 2915, 1476, 1476, 1476, 1476,
+     1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550,
+     1550, 1550, 1550, 1866, 1866, 1866, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1866, 1866, 1607, 1607, 1607, 1607,
+
+     1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607,  718,
+      718,  718,  718,  718,  718,  718,  718,  718,  718,  718,
+      718,  718, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
+     1024, 1024, 1024, 1024, 1024, 1029, 1029, 1029, 1029, 1029,
+     1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1034, 1034,
+     1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034,
+     1034, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282,
+     1282, 1282, 1282, 1282, 1287, 1287, 1287, 1287, 1287, 1287,
+     1287, 1287, 1287, 1287, 1287, 1287, 1287, 1292, 1292, 1292,
+     1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
+
+     1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297,
+     1297, 1297, 1297, 1303, 1303, 1303, 1303, 1303, 1303, 1303,
+     1303, 1303, 1303, 1303, 1303, 1303, 1308, 1308, 1308, 1308,
+     1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1313,
+     1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313,
+     1313, 1313, 1623, 1623, 1623, 1623, 1623, 1623, 1623, 1623,
+     1623, 1623, 1623, 1623, 1623, 1628, 1628, 1628, 1628, 1628,
+     1628, 1628, 1628, 1628, 1628, 1628, 1628, 1628, 1633, 1633,
+     1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633,
+     1633, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638,
+
+     1638, 1638, 1638, 1638, 1643, 1643, 1643, 1643, 1643, 1643,
+     1643, 1643, 1643, 1643, 1643, 1643, 1643, 1648, 1648, 1648,
+     1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,
+      738,  738,  738,  738,  738,  738,  738,  738,  738,  738,
+      738,  738,  738, 1043, 1043, 1043, 1043, 1043, 1043, 1043,
+     1043, 1043, 1043, 1043, 1043, 1043, 1048, 1048, 1048, 1048,
+     1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1053,
+     1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053,
+     1053, 1053, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319,
+     1319, 1319, 1319, 1319, 1319, 1324, 1324, 1324, 1324, 1324,
+
+     1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1329, 1329,
+     1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329,
+     1329, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334,
+     1334, 1334, 1334, 1334, 1340, 1340, 1340, 1340, 1340, 1340,
+     1340, 1340, 1340, 1340, 1340, 1340, 1340, 1345, 1345, 1345,
+     1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345,
+     1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350,
+     1350, 1350, 1350, 1653, 1653, 1653, 1653, 1653, 1653, 1653,
+     1653, 1653, 1653, 1653, 1653, 1653, 1658, 1658, 1658, 1658,
+     1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1663,
+
+     1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663,
+     1663, 1663, 1668, 1668, 1668, 1668, 1668, 1668, 1668, 1668,
+     1668, 1668, 1668, 1668, 1668, 1673, 1673, 1673, 1673, 1673,
+     1673, 1673, 1673, 1673, 1673, 1673, 1673, 1673, 1678, 1678,
+     1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678,
+     1678,  726,  726,  726,  726,  726,  726,  726,  726,  726,
+      726,  726,  726,  450,  450,  450,  450,  450, 2915,  450,
+      450,  450,  450, 1373, 1373, 1373, 1373, 1373, 1373, 1373,
+     1373, 2915, 1373, 1373, 1373, 1373, 1413, 1413, 1413, 1413,
+     1413, 1413, 1413, 1413, 2915, 1413, 1413, 1413, 1413,  550,
+
+      550, 2915,  550,  550,  550,  550,  550,  550,  550,  550,
+      550,  550,  551,  551, 2915,  551,  551,  551,  551,  551,
+      551,  551,  551,  551,  551, 1734, 1734, 1734, 1734, 1734,
+     1734, 1734, 1734, 1734, 1734, 1734, 1734, 1734, 2013, 2013,
+     2013, 2013, 2013, 2013, 2013, 2013, 2915, 2013, 2013, 2013,
+     2013,  994,  994, 2915,  994,  994,  994,  994,  994,  994,
+      994,  994,  994,  994, 2024, 2024, 2024, 2024, 2024, 2024,
+     2024, 2024, 2024, 2024, 2024, 2024, 2024, 1476, 1476, 1476,
+     1476, 1476, 1476, 1476, 1476, 2915, 1476, 1476, 1476, 1476,
+     2093, 2093, 2093, 2093, 2093, 2093, 2093, 2093, 2093, 2093,
+
+     2093, 2093, 2093, 1866, 1866, 1866, 1866, 1866, 1866, 1866,
+     1866, 1866, 1866, 1866, 1866, 1866, 1607, 1607, 1607, 1607,
+     1607, 1607, 1607, 1607, 2915, 1607, 1607, 1607, 1607, 1403,
+     1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403,
+     1403, 1403, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
+     1467, 1467, 1467, 1467, 1467,  976,  976,  976,  976,  976,
+      976,  976,  976,  976,  976,  976,  976,  976, 2174, 2174,
+     2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174, 2174,
+     2174, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135,
+     1135, 1135, 1135, 1135, 1421, 1421, 1421, 1421, 1421, 1421,
+
+     1421, 1421, 1421, 1421, 1421, 1421, 1421, 2815, 2815, 2815,
+     2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815, 2815,
+      123, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915
+    } ;
+
+static yyconst flex_int16_t yy_chk[27006] =
+    {   0,
+        0,    1,    1,  320,    1,    1,    1,  320,    1,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    3,    3,    3,    3,    3,    3,    3,
+
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    7,  144,    7,    7,    8,  144,    8,    8,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+
+       15,   15,   15,   15,   15,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17,   17,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   21,   21,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+
+       27,   27,   27,   27,   27,   27,   27,   27,   27,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   31,   31,   31,   31,   31,   31,   31,
+
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
+       31,   31,   31,   31,   31,   31,   31,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
+       33,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
+       35,   35,   35,   35,   35,   37,  145,   37,   37,   38,
+      145,   38,   38,   39,  468,   39,   39,   40,  468,   40,
+       40,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   41,   41,   41,   41,   41,
+       41,   41,   41,   41,   41,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+
+       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   49,  331,   49,
+
+       49,   50,  469,   50,   50,   51,  469,   51,   51,   52,
+       51,   52,   52,   53,   52,   53,   53,   54,  134,   54,
+       54,   63,  134,   63,   63,   64, 3332,   64,   64,  138,
+       65,   63,   65,   65,   66,   64,   66,   66,  138,  134,
+      152,   65,  152,   65,  517,   66,   67,   66,   67,   67,
+       68,  517,   68,   68,  142,   79,   79,   67,   79,   79,
+      142,   68,   85,   53,   85,   85,  331,   54,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   57,   57,   57,   57,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+
+       61,   61,   61,   61,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   73,   73,   73,   73,
+       73,   73,   73,   73,   73,   73,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   77,   77,   80,   80, 3190,   80,   80,   81,
+       81,  462,   81,   81,   82,   82,  488,   82,   82,   86,
+      462,   86,   86,   87,   87,  488,   87,   87,  466,   88,
+       88,   81,   88,   88,  466, 3011,   82,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
+       83,   89, 2913,   89,   89,   90,  200,   90,   90,   93,
+       93,  201,   93,   93,   94,   94,  135,   94,   94,  135,
+      490,  490,  135,  135,  135,  137,  137,  200,  137,  486,
+       89,  137,  201,  486,   90,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,   91,   91,   95,
+     2910,   95,   95,   96,  139,   96,   96,  154,  105,  452,
+      105,  105,  139,  452,  143,  499,  493,  139,  143,  493,
+      154,  154,  143,  154,  139,  520,  499,  143,   95,  105,
+      452,  520,   96,   97,   97,   97,   97,   97,   97,   97,
+
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,   99,   99,   99,   99,   99,   99,   99,   99,   99,
+       99,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  101,  101,  101,  101,  101,
+      101,  101,  101,  101,  101,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  106,
+      141,  106,  106,  476, 2908,  476,  141,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  141, 2907,  141,
+      106,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  107,  107,  107,  107,  107,
+      107,  107,  107,  107,  107,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  109,
+      109,  109,  109,  109,  109,  109,  109,  109,  109,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+      111,  111,  111,  111,  111,  111,  111,  111,  111,  111,
+
+      111,  111,  111,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  113,  113,  113,
+      113,  113,  113,  113,  113,  113,  113,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  115,  115,  115,  115,  115,  115,  115,  115,  115,
+      115,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  117,  117,  117,  117,  117,
+      117,  117,  117,  117,  117,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
+      119,  119,  119,  119,  119,  119,  119,  119,  119,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  121,  121,  121,  121,  121,  121,  121,
+      121,  121,  121,  130,  147,  149,  316,  130,  332,  149,
+      483,  504,  483,  504,  316,  512,  316,  147,  149,  149,
+      147,  147,  150,  147,  130,  334,  150,  512,  508,  150,
+      150,  461,  461,  534,  461,  150,  150,  461,  534,  150,
+      150,  150,  151,  151,  317,  150,  151,  506,  151,  508,
+      151,  506,  317,  525,  317,  151,  525,  151, 2905,  151,
+      183,  183,  183,  183,  183,  183,  183,  183,  183,  183,
+      332,  545, 2904,  545,  130,  130,  130,  130,  130,  130,
+
+      130,  130,  130,  130,  131,  131,  131,  131,  131,  131,
+      334,  131, 2901,  131,  131,  131,  131,  131,  131,  131,
+      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
+      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
+      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
+      131,  131,  131,  131,  131,  131,  131,  184,  184,  184,
+      184,  184,  184,  184,  184,  184,  184,  459,  481,  197,
+      459, 2899,  481,  459,  459,  459,  131,  131,  131,  131,
+      131,  131,  131,  131,  131,  131,  132,  527,  478,  481,
+      132,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+
+      188,  478,  478,  964,  478,  527,  964,  132,  189,  189,
+      189,  189,  189,  189,  189,  189,  189,  189,  197,  197,
+      197,  197,  197,  197,  197,  197,  197,  197,  202,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  203,  203,
+      203,  203,  203,  203,  203,  203,  203,  203,  526,  530,
+      542,  586,  535,  530,  526,  542, 2896,  132,  132,  132,
+      132,  132,  132,  132,  132,  132,  132,  156,  535,  884,
+      884,  156,  586,  156,  207,  207,  207,  207,  207,  207,
+      207,  207,  207,  207,  208,  208,  208,  208,  208,  208,
+      208,  208,  208,  208,  212,  212,  212,  212,  212,  212,
+
+      212,  212,  212,  212,  213,  213,  213,  213,  213,  213,
+      213,  213,  213,  213,  865,  875,  865,  875,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  217,  217,  217,
+      217,  217,  217,  217,  217,  217,  217,  156,  156,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  173,  173,  173,  173,  173,  173,  173,
+      173,  173,  173,  178,  218,  218,  218,  218,  218,  218,
+      218,  218,  218,  218,  222,  222,  222,  222,  222,  222,
+      222,  222,  222,  222,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  179,  179,  179,  179,  179,  179,  179,
+
+      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
+      179,  179,  180,  180,  180,  180,  180,  180,  180,  180,
+      180,  180,  180,  180,  180,  180,  180,  180,  180,  180,
+      180,  185,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  232,  232,  232,  232,  232,  232,  232,  232,
+      232,  232,  233,  233,  233,  233,  233,  233,  233,  233,
+      233,  233,  237,  237,  237,  237,  237,  237,  237,  237,
+      237,  237,  538,  717,  864,  885,  885,  717,  864,  538,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  238,
+
+      238,  238,  238,  238,  238,  238,  238,  238,  238,  185,
+      185,  190,  242,  242,  242,  242,  242,  242,  242,  242,
+      242,  242,  243,  243,  243,  243,  243,  243,  243,  243,
+      243,  243,  247,  247,  247,  247,  247,  247,  247,  247,
+      247,  247,  248,  248,  248,  248,  248,  248,  248,  248,
+      248,  248,  873,  874,  887,  887,  920,  873,  920,  874,
+      190,  190,  190,  190,  190,  190,  190,  190,  190,  190,
+      190,  190,  190,  190,  190,  190,  190,  190,  190,  252,
+      252,  252,  252,  252,  252,  252,  252,  252,  252,  190,
+      190,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  193,  193,  193,  193,  193,
+      193,  193,  193,  193,  193,  199,  253,  253,  253,  253,
+      253,  253,  253,  253,  253,  253,  511,  513,  548,  890,
+      511,  513,  548,  890,  199,  262,  262,  262,  262,  262,
+
+      262,  262,  262,  262,  262,  263,  263,  263,  263,  263,
+      263,  263,  263,  263,  263,  867,  513,  889,  889,  896,
+      896,  548,  511,  867,  199,  199,  199,  199,  199,  199,
+      199,  199,  199,  199,  199,  199,  199,  199,  199,  199,
+      199,  199,  199,  199,  199,  199,  199,  199,  199,  199,
+      199,  199,  199,  199,  199,  204,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  267,  268,  268,  268,  268,
+      268,  268,  268,  268,  268,  268,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  877,  888,  894,  942,
+
+      942,  877,  894,  888,  204,  204,  204,  204,  204,  204,
+      204,  204,  204,  204,  204,  204,  204,  204,  204,  204,
+      204,  204,  204,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  204,  204,  209,  278,  278,  278,  278,
+      278,  278,  278,  278,  278,  278,  295,  295,  295,  295,
+      295,  295,  295,  295,  295,  295,  296,  296,  296,  296,
+      296,  296,  296,  296,  296,  296,  300,  300,  300,  300,
+      300,  300,  300,  300,  300,  300,  900,  915,  970, 1453,
+     1453,  915,  900,  970,  209,  209,  209,  209,  209,  209,
+      209,  209,  209,  209,  209,  209,  209,  209,  209,  209,
+
+      209,  209,  209,  301,  301,  301,  301,  301,  301,  301,
+      301,  301,  301,  209,  209,  214,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  306,  306,  306,  306,
+      306,  306,  306,  306,  306,  306,  310,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,  311,  311,  311,  311,
+      311,  311,  311,  311,  311,  311,  549,  939, 2893, 1091,
+      549, 1091,  587,  594,  214,  214,  214,  214,  214,  214,
+      214,  214,  214,  214,  214,  214,  214,  214,  214,  214,
+      214,  214,  214,  587,  594,  927,  929,  745,  318, 2891,
+      939,  927,  929,  214,  214,  219,  318,  549,  318,  324,
+
+      324,  324,  324,  324,  324,  324,  324,  324,  324,  325,
+      325,  325,  325,  325,  325,  325,  325,  325,  325,  326,
+      326,  326,  326,  326,  326,  326,  326,  326,  326,  329,
+      329,  329,  329,  329,  329,  329,  329,  329,  329,  745,
+      745, 1094, 2889, 1094,  219,  219,  219,  219,  219,  219,
+      219,  219,  219,  219,  219,  219,  219,  219,  219,  219,
+      219,  219,  219,  340,  340,  340,  340,  340,  340,  340,
+      340,  340,  340,  219,  219,  224,  341,  341,  341,  341,
+      341,  341,  341,  341,  341,  341,  345,  345,  345,  345,
+      345,  345,  345,  345,  345,  345,  346,  346,  346,  346,
+
+      346,  346,  346,  346,  346,  346,  350,  350,  350,  350,
+      350,  350,  350,  350,  350,  350,  956,  957, 1108, 1124,
+     1108, 1124,  956,  957,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  224,  224,  224,  224,  224,  224,  224,
+      224,  224,  224,  351,  351,  351,  351,  351,  351,  351,
+      351,  351,  351,  224,  224,  229,  355,  355,  355,  355,
+      355,  355,  355,  355,  355,  355,  356,  356,  356,  356,
+      356,  356,  356,  356,  356,  356,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  369,  369,  369,  369,
+      369,  369,  369,  369,  369,  369,  984,  985, 1066, 1143,
+
+      984, 1143, 1066,  985,  229,  229,  229,  229,  229,  229,
+      229,  229,  229,  229,  229,  229,  229,  229,  229,  229,
+      229,  229,  229,  377,  377,  377,  377,  377,  377,  377,
+      377,  377,  377,  229,  229,  234,  378,  378,  378,  378,
+      378,  378,  378,  378,  378,  378,  386,  386,  386,  386,
+      386,  386,  386,  386,  386,  386,  387,  387,  387,  387,
+      387,  387,  387,  387,  387,  387,  391,  391,  391,  391,
+      391,  391,  391,  391,  391,  391, 1068, 1109, 1242, 1123,
+     1068, 1242, 1109, 1123,  234,  234,  234,  234,  234,  234,
+      234,  234,  234,  234,  234,  234,  234,  234,  234,  234,
+
+      234,  234,  234,  392,  392,  392,  392,  392,  392,  392,
+      392,  392,  392,  234,  234,  239,  396,  396,  396,  396,
+      396,  396,  396,  396,  396,  396,  397,  397,  397,  397,
+      397,  397,  397,  397,  397,  397,  409,  409,  409,  409,
+      409,  409,  409,  409,  409,  409,  410,  410,  410,  410,
+      410,  410,  410,  410,  410,  410, 1111, 1112, 1152, 1181,
+     1152, 1181, 1111, 1112,  239,  239,  239,  239,  239,  239,
+      239,  239,  239,  239,  239,  239,  239,  239,  239,  239,
+      239,  239,  239,  414,  414,  414,  414,  414,  414,  414,
+      414,  414,  414,  239,  239,  244,  415,  415,  415,  415,
+
+      415,  415,  415,  415,  415,  415,  419,  419,  419,  419,
+      419,  419,  419,  419,  419,  419,  420,  420,  420,  420,
+      420,  420,  420,  420,  420,  420,  429,  429,  429,  429,
+      429,  429,  429,  429,  429,  429, 1115, 1142, 1188, 1190,
+     1188, 1190, 1142, 1115,  244,  244,  244,  244,  244,  244,
+      244,  244,  244,  244,  244,  244,  244,  244,  244,  244,
+      244,  244,  244,  430,  430,  430,  430,  430,  430,  430,
+      430,  430,  430,  244,  244,  249,  434,  434,  434,  434,
+      434,  434,  434,  434,  434,  434,  435,  435,  435,  435,
+      435,  435,  435,  435,  435,  435,  439,  439,  439,  439,
+
+      439,  439,  439,  439,  439,  439,  440,  440,  440,  440,
+      440,  440,  440,  440,  440,  440,  729,  728, 1170, 1192,
+     2888, 1192, 1170,  744,  249,  249,  249,  249,  249,  249,
+      249,  249,  249,  249,  249,  249,  249,  249,  249,  249,
+      249,  249,  249,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  249,  249,  254,  445,  445,  445,  445,
+      445,  445,  445,  445,  445,  445,  463,  467,  473, 2884,
+      465,  467,  473,  903,  463,  467,  465,  471,  729,  463,
+      467,  473,  903,  497,  518,  728,  463,  465,  518,  465,
+      471,  497,  744,  471,  471,  492,  471,  497, 1158,  492,
+
+      731,  497,  497, 1158,  254,  254,  254,  254,  254,  254,
+      254,  254,  254,  254,  254,  254,  254,  254,  254,  254,
+      254,  254,  254,  474,  516,  492,  518,  474,  516,  876,
+      474,  474, 2883,  254,  254,  264,  474,  474,  492,  876,
+      474,  474,  474,  475,  475,  713,  474,  475, 2880,  475,
+      561,  475,  928,  713,  561,  713,  475,  516,  475,  872,
+      475,  928,  516,  528,  714,  731,  533,  528,  516,  561,
+      533,  872,  714,  866,  714,  540, 1160,  866,  521,  540,
+     2878,  895,  521, 1160,  264,  264,  264,  264,  264,  264,
+      264,  264,  264,  264,  264,  264,  264,  264,  264,  264,
+
+      264,  264,  264,  521,  528,  584,  967,  528,  533,  521,
+      866,  866,  540,  264,  264,  269,  540,  895,  967,  540,
+     1218, 2877, 1218,  521,  570,  570,  570,  570,  570,  570,
+      570,  570,  570,  570,  576,  576,  576,  576,  576,  576,
+      576,  576,  576,  576,  897,  899, 1187,  588, 1228, 2873,
+     1228, 1187,  897,  899,  584,  584,  584,  584,  584,  584,
+      584,  584,  584,  584,  269,  269,  269,  269,  269,  269,
+      269,  269,  269,  269,  269,  269,  269,  269,  269,  269,
+      269,  269,  269,  596,  596,  596,  596,  596,  596,  596,
+      596,  596,  596,  269,  269,  274,  588,  588,  588,  588,
+
+      588,  588,  588,  588,  588,  588,  602,  602,  602,  602,
+      602,  602,  602,  602,  602,  602,  608,  608,  608,  608,
+      608,  608,  608,  608,  608,  608,  614,  614,  614,  614,
+      614,  614,  614,  614,  614,  614, 1126, 1161, 1237, 2872,
+     1237, 1161, 1126, 1161,  274,  274,  274,  274,  274,  274,
+      274,  274,  274,  274,  274,  274,  274,  274,  274,  274,
+      274,  274,  274,  620,  620,  620,  620,  620,  620,  620,
+      620,  620,  620,  274,  274,  279,  626,  626,  626,  626,
+      626,  626,  626,  626,  626,  626,  632,  632,  632,  632,
+      632,  632,  632,  632,  632,  632,  638,  638,  638,  638,
+
+      638,  638,  638,  638,  638,  638,  644,  644,  644,  644,
+      644,  644,  644,  644,  644,  644, 1162, 1163, 1254, 1278,
+     1254, 1278, 1162, 1163,  279,  279,  279,  279,  279,  279,
+      279,  279,  279,  279,  279,  279,  279,  279,  279,  279,
+      279,  279,  279,  650,  650,  650,  650,  650,  650,  650,
+      650,  650,  650,  279,  279,  297,  656,  656,  656,  656,
+      656,  656,  656,  656,  656,  656,  664,  664,  664,  664,
+      664,  664,  664,  664,  664,  664,  670,  670,  670,  670,
+      670,  670,  670,  670,  670,  670,  676,  676,  676,  676,
+      676,  676,  676,  676,  676,  676, 1166, 1241, 1356, 1593,
+
+     1593, 1241, 1356, 1166,  297,  297,  297,  297,  297,  297,
+      297,  297,  297,  297,  297,  297,  297,  297,  297,  297,
+      297,  297,  297,  682,  682,  682,  682,  682,  682,  682,
+      682,  682,  682,  297,  297,  302,  689,  689,  689,  689,
+      689,  689,  689,  689,  689,  689,  695,  695,  695,  695,
+      695,  695,  695,  695,  695,  695,  701,  701,  701,  701,
+      701,  701,  701,  701,  701,  701,  707,  707,  707,  707,
+      707,  707,  707,  707,  707,  707,  718, 1225, 1357, 1907,
+     2869, 1907, 1357, 1225,  302,  302,  302,  302,  302,  302,
+      302,  302,  302,  302,  302,  302,  302,  302,  302,  302,
+
+      302,  302,  302,  726,  726,  726,  726,  726,  726,  726,
+      726,  726,  726,  302,  302,  307,  753,  753,  753,  753,
+      753,  753,  753,  753,  753,  753,  719,  901,  977,  948,
+      902,  719,  879, 1002, 2149, 2149,  879,  901,  902,  948,
+     1083,  718,  718,  718,  718,  718,  718,  718,  718,  718,
+      718,  720,  937,  879, 1002, 1360,  720, 1083, 2867, 1360,
+      937,  977,  739,  738,  307,  307,  307,  307,  307,  307,
+      307,  307,  307,  307,  307,  307,  307,  307,  307,  307,
+      307,  307,  307,  738,  738,  738,  738,  738,  738,  738,
+      738,  738,  738,  307,  307,  312,  719,  719,  719,  719,
+
+      719,  719,  719,  719,  719,  719,  721,  943,  983,  940,
+      951,  721,  739,  940, 2865,  943,  740,  983,  940, 1186,
+      951,  720,  720,  720,  720,  720,  720,  720,  720,  720,
+      720, 1186,  739,  739,  739,  739,  739,  739,  739,  739,
+      739,  739,  749, 2861,  312,  312,  312,  312,  312,  312,
+      312,  312,  312,  312,  312,  312,  312,  312,  312,  312,
+      312,  312,  312,  869,  878,  880,  740,  869,  878,  880,
+     2776, 2776, 2857,  312,  312,  337,  721,  721,  721,  721,
+      721,  721,  721,  721,  721,  721,  740,  740,  740,  740,
+      740,  740,  740,  740,  740,  740,  741,  748,  880, 1098,
+
+      869,  878,  880, 1370,  869, 1087,  749, 1370,  749,  749,
+     1098,  749,  337,  337,  337, 1087,  337,  337,  337,  337,
+      337,  337,  337,  337,  337,  337,  337,  337,  337,  337,
+      337,  337,  337,  337,  337,  337,  337,  337,  337,  337,
+      342,  893, 1093,  893, 1505,  893,  741,  893,  748,  907,
+      986,  748, 1093,  907,  893,  748, 1159, 1090, 1159,  986,
+      748, 1090, 1505, 2856,  748, 1159,  741,  741,  741,  741,
+      741,  741,  741,  741,  741,  741,  759,  759,  759,  759,
+      759,  759,  759,  759,  759,  759,  907, 2847, 1090,  342,
+      342,  342,  342,  342,  342,  342,  342,  342,  342,  342,
+
+      342,  342,  342,  342,  342,  342,  342,  342,  765,  765,
+      765,  765,  765,  765,  765,  765,  765,  765,  342,  342,
+      347,  771,  771,  771,  771,  771,  771,  771,  771,  771,
+      771,  779,  779,  779,  779,  779,  779,  779,  779,  779,
+      779,  787,  787,  787,  787,  787,  787,  787,  787,  787,
+      787,  795,  795,  795,  795,  795,  795,  795,  795,  795,
+      795, 1184, 1252, 2778, 2778, 2780, 2780, 1252, 1184,  347,
+      347,  347,  347,  347,  347,  347,  347,  347,  347,  347,
+      347,  347,  347,  347,  347,  347,  347,  347,  801,  801,
+      801,  801,  801,  801,  801,  801,  801,  801,  347,  347,
+
+      352,  807,  807,  807,  807,  807,  807,  807,  807,  807,
+      807,  817,  817,  817,  817,  817,  817,  817,  817,  817,
+      817,  823,  823,  823,  823,  823,  823,  823,  823,  823,
+      823,  829,  829,  829,  829,  829,  829,  829,  829,  829,
+      829, 1227, 1268, 2845, 2844, 2842, 2834, 1227, 1268,  352,
+      352,  352,  352,  352,  352,  352,  352,  352,  352,  352,
+      352,  352,  352,  352,  352,  352,  352,  352,  838,  838,
+      838,  838,  838,  838,  838,  838,  838,  838,  352,  352,
+      357,  844,  844,  844,  844,  844,  844,  844,  844,  844,
+      844,  850,  850,  850,  850,  850,  850,  850,  850,  850,
+
+      850,  856,  856,  856,  856,  856,  856,  856,  856,  856,
+      856, 1095, 1096, 2826, 1110, 2825, 1118, 1119, 1096,  892,
+     1165, 1095, 1096,  892, 1110, 1096, 1118, 1119, 1165,  357,
+      357,  357,  357,  357,  357,  357,  357,  357,  357,  357,
+      357,  357,  357,  357,  357,  357,  357,  357,  868,  870,
+      881,  882,  868,  870,  881,  882,  892,  898,  357,  357,
+      370,  898,  892, 2802, 1155,  906, 2800,  904,  868,  906,
+      870,  904,  925,  882,  954, 1155,  925, 1107,  954,  881,
+     1085, 1107, 1168, 2799, 1085,  868,  898,  881,  882,  904,
+      870, 1168, 1229,  925,  898,  954,  904, 1189,  906,  912,
+
+      925, 1085,  906,  912,  904, 1229, 2798, 1189, 1107,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  370,  370,  908,  909,
+      910,  911,  908,  909,  910,  911,  912, 2797,  370,  370,
+      379,  913,  914,  916,  919,  913,  914,  916,  919,  908,
+      921, 2796, 1113,  911,  921,  910, 1113,  914,  909, 1164,
+     1164, 1164,  913, 1173, 1173,  908,  909,  910,  911, 2795,
+     1220, 1164, 1374,  938, 1173, 1270, 1374,  938,  913,  914,
+      916,  919, 1220, 1113,  926, 2773, 1270,  921,  926,  379,
+      379,  379,  379,  379,  379,  379,  379,  379,  379,  379,
+
+      379,  379,  379,  379,  379,  379,  379,  379,  917,  924,
+      938,  932,  917,  924, 2772,  932,  926,  938,  379,  379,
+      388,  926,  933, 1274,  934,  944,  933,  941,  934,  944,
+      935,  941, 1191, 1274,  935,  917,  917,  924, 1381,  932,
+     1191, 2771, 1381,  917, 2770,  917,  924,  917,  932,  917,
+      917,  933,  917,  934,  917,  935,  947,  941,  944,  933,
+      947,  934,  944,  944,  941, 2769, 2760,  935, 2759,  388,
+      388,  388,  388,  388,  388,  388,  388,  388,  388,  388,
+      388,  388,  388,  388,  388,  388,  388,  388,  918, 2752,
+      950, 1382,  918,  947,  950, 1382, 2750,  947,  388,  388,
+
+      393,  930,  936,  966,  946,  930,  936,  966,  946,  918,
+     1114,  950,  950, 1382, 1114,  918,  918, 1116, 2748, 2746,
+     2468, 1116,  936,  918,  966,  918,  930,  918,  930,  918,
+      918, 1114,  918,  952,  918, 2468,  930,  952,  930,  936,
+      930,  946,  930,  930,  930,  966, 2745,  946, 1116,  393,
+      393,  393,  393,  393,  393,  393,  393,  393,  393,  393,
+      393,  393,  393,  393,  393,  393,  393,  393,  931,  949,
+      952, 1905,  931,  949, 2744,  952, 2742, 1905,  393,  393,
+      398,  945, 2740,  953,  955,  945,  965,  953,  955,  931,
+      965,  949, 1383,  931, 1134,  931, 1383, 2739, 1134, 2722,
+
+     2713, 1204,  945,  931,  975, 1204,  949,  931,  975,  931,
+      931,  931,  968,  972,  945, 1134,  968,  972,  945,  945,
+      953,  955, 1204,  965,  975,  975, 2712,  955,  965,  398,
+      398,  398,  398,  398,  398,  398,  398,  398,  398,  398,
+      398,  398,  398,  398,  398,  398,  398,  398,  971,  968,
+      972,  972,  971,  979, 2711, 2710, 2709,  979,  398,  398,
+      411,  987,  988,  989, 2707,  987,  988,  989,  991,  993,
+     1387, 2702,  991,  993, 1387,  979, 1213,  971, 2698, 1217,
+     1213, 1250,  979, 1217,  989,  971, 1024,  988,  989, 2697,
+      979,  990, 2694, 1250, 2692,  990, 1213, 1213,  987,  988,
+
+     1217,  988,  989, 1025, 1086,  991,  993,  993, 1086,  411,
+      411,  411,  411,  411,  411,  411,  411,  411,  411,  411,
+      411,  411,  411,  411,  411,  411,  411,  411,  990,  992,
+     2688, 2686, 1388,  992,  990, 1086, 1388, 1273,  411,  411,
+      416, 1369, 1101, 1086, 1121, 1369, 1101, 2684, 1121, 1273,
+      992, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
+     1024, 2682, 1026, 1101, 2681, 1121,  992, 1026, 1025, 1025,
+     1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1027, 1101,
+     2680, 1121, 1401, 1027, 1369, 2679, 1401, 2678, 1043,  416,
+      416,  416,  416,  416,  416,  416,  416,  416,  416,  416,
+
+      416,  416,  416,  416,  416,  416,  416,  416, 1043, 1043,
+     1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043,  416,  416,
+      421, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058,
+     1058, 2677, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
+     1026, 1026, 1028, 2676, 2675, 2657, 2651, 1028, 1027, 1027,
+     1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1029, 2650,
+     1409, 1410, 1392, 1029, 1409, 1410, 1392, 2649, 1044,  421,
+      421,  421,  421,  421,  421,  421,  421,  421,  421,  421,
+      421,  421,  421,  421,  421,  421,  421,  421, 1044, 1044,
+     1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044,  421,  421,
+
+      431, 2648, 1368, 1089, 1392, 1157, 1368, 1089, 2647, 1157,
+     2646, 2644, 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1028,
+     1028, 1028, 1031, 1089, 1089, 1089, 1157, 1031, 1029, 1029,
+     1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1032, 2640,
+     1368, 1102, 1127, 1032, 1097, 1102, 1127, 1157, 1097,  431,
+      431,  431,  431,  431,  431,  431,  431,  431,  431,  431,
+      431,  431,  431,  431,  431,  431,  431,  431, 2638, 1097,
+     1127, 2636, 1102, 1127, 2634, 1097, 2633, 1418,  431,  431,
+      436, 1418, 1102, 1104, 1395, 1141, 1389, 1104, 1395, 1141,
+     1389, 2630, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031,
+
+     1031, 1031, 1033, 2628, 1104, 1104, 1141, 1033, 1032, 1032,
+     1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1034, 1389,
+     1099, 1122, 1141, 1034, 1099, 1122, 2624, 1395, 2617,  436,
+      436,  436,  436,  436,  436,  436,  436,  436,  436,  436,
+      436,  436,  436,  436,  436,  436,  436,  436, 2615, 1129,
+     1422, 1099, 1122, 1129, 1422, 2614, 2613, 1099,  436,  436,
+      441, 1427, 1122, 2612, 1150, 1427, 1129, 1129, 1150, 2611,
+     1129, 1129, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033,
+     1033, 1033, 1036, 2610, 2609, 1150, 1150, 1036, 1034, 1034,
+     1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1037, 2608,
+
+     1100, 1130, 1145, 1037, 1100, 1130, 1145, 2591, 2587,  441,
+      441,  441,  441,  441,  441,  441,  441,  441,  441,  441,
+      441,  441,  441,  441,  441,  441,  441,  441, 2580, 2579,
+     1147, 1100, 1130, 1145, 1147, 2578, 2577, 1100,  441,  441,
+      446, 1219, 1179, 1210, 1207, 1219, 1179, 1210, 1207, 2576,
+     2575, 1147, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036,
+     1036, 1036, 1219, 1179, 1210, 1207, 2569, 1147, 1037, 1037,
+     1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1038, 1179,
+     1120, 1207, 1396, 1038, 1120, 1210, 1396, 2565, 1045,  446,
+      446,  446,  446,  446,  446,  446,  446,  446,  446,  446,
+
+      446,  446,  446,  446,  446,  446,  446,  446, 1125, 1128,
+     1376, 1120, 1125, 1128, 1376, 2563, 2561, 1120,  446,  446,
+      450, 1396, 2560, 2559,  450, 1385, 1128, 1128, 1125, 1385,
+     1376, 1128, 1376, 1400, 2558, 2555, 1046, 1400, 1045, 1125,
+     1128,  450, 1140, 1146, 2553, 2540, 1140, 1146, 1038, 1038,
+     1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1045, 1045,
+     1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1047, 1400,
+     1385, 1183, 1202, 1140, 1146, 1183, 1202, 1430, 1048, 1140,
+     1146, 1430, 2535, 1223, 1393, 1154, 1046, 1223, 1393, 1154,
+     2533,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+
+      450,  451, 1183, 1202, 1223,  451, 1046, 1046, 1046, 1046,
+     1046, 1046, 1046, 1046, 1046, 1046, 1154, 2532, 1047, 1050,
+     1223, 1393,  451, 2531, 1154, 1429, 2530, 1148, 1048, 1429,
+     1178, 1148, 1203, 1051, 1178, 2529, 1203, 2528, 1047, 1047,
+     1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1048, 1048,
+     1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1148, 2527,
+     2526, 1178, 1429, 1203, 1235, 2502, 2499, 1178, 1235, 1050,
+     1148, 2489,  451,  451,  451,  451,  451,  451,  451,  451,
+      451,  451,  454, 1051, 2488, 1235,  454, 2479,  454, 1050,
+     1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 2476,
+
+     2469, 2467, 1052, 1051, 1051, 1051, 1051, 1051, 1051, 1051,
+     1051, 1051, 1051, 2466, 2463, 1431, 1443, 1442, 1434, 1431,
+     1443, 1442, 1434, 1156, 1176, 1208, 1447, 1156, 1176, 1208,
+     1447, 2456, 2453,  454,  454,  454,  454,  454,  454,  454,
+      454,  454,  454,  454,  454,  454,  454,  454,  454,  454,
+      454,  454, 1052, 1180, 1156, 1176, 1208, 1180, 1431, 1434,
+     1442, 2451,  454,  454,  457, 1156, 1208, 1176,  457, 2438,
+     2437, 2436, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052,
+     1052, 1052, 1180, 1391, 1180, 2434, 2433, 1391, 2432,  457,
+      457,  457,  457,  457,  457, 2431,  457,  457, 2430,  457,
+
+      457,  457,  457,  457,  457,  457,  457,  457,  457,  457,
+      457, 2406, 1391,  457,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  543,  543,
+      543,  543,  543,  543,  543,  543,  543,  543,  560,  560,
+
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+      560,  560,  565, 1177, 1185, 1206, 1212, 1177, 1185, 1206,
+     1212, 1239, 1451, 2405, 2400, 1239, 1451, 1256, 1262, 2398,
+
+     2386, 1256, 1262, 1177, 1185, 1454, 1212, 1455, 2385, 1454,
+     2384, 1455, 1239, 1239, 1177, 1185, 1206, 1212, 1256, 1262,
+     2380, 1177, 1206,  565,  565,  565,  565,  565,  565,  565,
+      565,  565,  565,  565,  565,  565,  565,  565,  565,  565,
+      565,  565,  566,  566,  566,  566,  566,  566,  566,  566,
+      566,  566,  566,  566,  566,  566,  566,  566,  566,  566,
+      566,  567,  567,  567,  567,  567,  567,  567,  567,  567,
+      567,  567,  567,  567,  567,  567,  567,  567,  567,  567,
+      569,  569,  569,  569,  569,  569,  569,  569,  569,  569,
+      569,  569,  569,  569,  569,  569,  569,  569,  569,  571,
+
+     1131, 1200, 1214, 1209, 1131, 1200, 1214, 1209, 1216, 1445,
+     2379, 2370, 1216, 1445, 1367, 1221, 1272, 1053, 1367, 1221,
+     1272, 1472, 1131, 1473, 2369, 1472, 1200, 1473, 1200, 1445,
+     1055, 1131, 1200, 1214, 1209, 1367, 1200, 1272, 1272, 1216,
+     1200, 1131, 1200, 1200, 1200, 1209, 1221, 1056,  571,  571,
+      571,  571,  571,  571,  571,  571,  571,  571,  571,  571,
+      571,  571,  571,  571,  571,  571,  571, 1053, 1205, 1457,
+     1490, 1390, 1205, 1457, 1490, 1390, 2366,  571,  571,  577,
+     1055, 1224, 1215, 2359, 1457, 1224, 1215, 1053, 1053, 1053,
+     1053, 1053, 1053, 1053, 1053, 1053, 1053, 1056, 1390, 1205,
+
+     1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055,
+     1215, 1224, 1224, 1215, 2358, 1205, 1490, 1056, 1056, 1056,
+     1056, 1056, 1056, 1056, 1056, 1056, 1056, 1319,  577,  577,
+      577,  577,  577,  577,  577,  577,  577,  577,  577,  577,
+      577,  577,  577,  577,  577,  577,  577, 1319, 1319, 1319,
+     1319, 1319, 1319, 1319, 1319, 1319, 1319,  577,  577,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  582,  582,  582,  582,  582,  582,  582,
+      582,  582,  582,  585, 1201, 1211, 1233, 1222, 1201, 1211,
+     1233, 1222, 1259, 1432, 1384, 2356, 1259, 1432, 1384, 1234,
+     1238, 2355,  585, 1234, 1238, 1201, 1509, 2352, 1512, 1201,
+     1509, 1201, 1512, 1259, 1057, 1384, 1211, 1233, 1222, 1201,
+     1432, 2340, 1238, 1201, 1222, 1201, 1201, 1201, 1211, 1259,
+     1234, 1238,  585,  585,  585,  585,  585,  585,  585,  585,
+
+      585,  585,  585,  585,  585,  585,  585,  585,  585,  585,
+      585,  585,  585,  585,  585,  585,  585,  585,  585,  585,
+      585,  585,  585,  589, 1057, 1240, 1245, 1236, 1247, 1240,
+     1245, 1236, 1247, 1246, 1253, 1248, 1483, 1246, 1253, 1248,
+     1483, 2335, 2333, 2327, 1057, 1057, 1057, 1057, 1057, 1057,
+     1057, 1057, 1057, 1057, 1236, 1248, 1240, 1245, 1236, 1247,
+     2324, 2311, 1246, 1243, 1246, 1253, 1248, 1243, 2310, 1245,
+     2309, 1483,  589,  589,  589,  589,  589,  589,  589,  589,
+      589,  589,  589,  589,  589,  589,  589,  589,  589,  589,
+      589, 1243, 1244, 1255, 1243, 1257, 1244, 1255, 2308, 1257,
+
+     1258,  589,  589,  597, 1258, 1243, 2307, 1260, 2306, 2305,
+     1263, 1260, 1265, 1244, 1263, 1267, 1265, 1269, 1264, 1267,
+     1244, 1269, 1264, 2304, 1255, 1257, 1257, 1263, 1263, 1461,
+     2303, 1258, 1263, 1461, 1244, 1264, 1264, 1258, 1260, 1264,
+     1264, 1263, 2280, 1265, 1260, 1277, 1267, 1460, 1269, 1277,
+     1282, 1460,  597,  597,  597,  597,  597,  597,  597,  597,
+      597,  597,  597,  597,  597,  597,  597,  597,  597,  597,
+      597, 1266, 1461, 1280, 1277, 1266, 1277, 1280, 2276, 2264,
+     1460,  597,  597,  603, 2263, 1397, 1283, 1372, 1280, 1397,
+     2260, 1372, 1394, 1266, 1284, 2257, 1394, 1398, 2252, 1284,
+
+     2236, 1398, 1266, 2234, 1280, 1285, 2233, 1372, 1372, 1372,
+     1285, 2229, 1266, 1394, 1397, 1282, 1282, 1282, 1282, 1282,
+     1282, 1282, 1282, 1282, 1282, 1286, 1398, 1516, 2228, 1394,
+     1286, 1516,  603,  603,  603,  603,  603,  603,  603,  603,
+      603,  603,  603,  603,  603,  603,  603,  603,  603,  603,
+      603, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283,
+     1283,  603,  603,  609, 1284, 1284, 1284, 1284, 1284, 1284,
+     1284, 1284, 1284, 1284, 2222, 1285, 1285, 1285, 1285, 1285,
+     1285, 1285, 1285, 1285, 1285, 1287, 2214, 1380, 1522, 1536,
+     1287, 1380, 1522, 1536, 2213, 1286, 1286, 1286, 1286, 1286,
+
+     1286, 1286, 1286, 1286, 1286, 1288, 2210, 1380, 1380, 1380,
+     1288, 1320,  609,  609,  609,  609,  609,  609,  609,  609,
+      609,  609,  609,  609,  609,  609,  609,  609,  609,  609,
+      609, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320,
+     1320,  609,  609,  615, 2208, 1408, 2205, 1412, 1428, 1408,
+     1433, 1412, 1428, 2203, 1433, 1287, 1287, 1287, 1287, 1287,
+     1287, 1287, 1287, 1287, 1287, 1289, 1408, 1408, 1412, 1428,
+     1289, 2202, 2196, 2191, 2186, 1288, 1288, 1288, 1288, 1288,
+     1288, 1288, 1288, 1288, 1288, 1290, 1433, 1437, 2183, 2181,
+     1290, 1437,  615,  615,  615,  615,  615,  615,  615,  615,
+
+      615,  615,  615,  615,  615,  615,  615,  615,  615,  615,
+      615, 1420, 1439, 1446, 1543, 1420, 1439, 1446, 1543, 2170,
+     1438,  615,  615,  621, 1438, 2168, 1448, 2166, 2162, 1437,
+     1448, 1420, 1420, 1446, 1446, 1289, 1289, 1289, 1289, 1289,
+     1289, 1289, 1289, 1289, 1289, 1291, 2161, 1544, 1456, 1438,
+     1291, 1544, 1456, 1448, 1439, 1290, 1290, 1290, 1290, 1290,
+     1290, 1290, 1290, 1290, 1290, 1292, 2156, 1440, 1448, 1456,
+     1292, 1440,  621,  621,  621,  621,  621,  621,  621,  621,
+      621,  621,  621,  621,  621,  621,  621,  621,  621,  621,
+      621, 1444, 2146, 1475, 1452, 1444, 1440, 1475, 1452, 2138,
+
+     1458,  621,  621,  627, 1458, 1449, 1450, 2135, 2134, 1449,
+     1450, 1452, 1452, 2133, 1475, 1291, 1291, 1291, 1291, 1291,
+     1291, 1291, 1291, 1291, 1291, 1293, 2132, 1450, 2131, 1458,
+     1293, 2130, 1444, 1449, 1450, 1292, 1292, 1292, 1292, 1292,
+     1292, 1292, 1292, 1292, 1292, 1294, 2129, 1449, 1450, 2128,
+     1294, 2127,  627,  627,  627,  627,  627,  627,  627,  627,
+      627,  627,  627,  627,  627,  627,  627,  627,  627,  627,
+      627, 1462, 1466, 1493, 1495, 1462, 1466, 1493, 1495, 2110,
+     1463,  627,  627,  633, 1463, 1467, 1468, 1487, 1526, 1467,
+     1468, 1487, 1526, 2109, 1466, 1293, 1293, 1293, 1293, 1293,
+
+     1293, 1293, 1293, 1293, 1293, 1295, 2106, 1467, 1468, 1463,
+     1295, 1493, 1487, 1495, 1462, 1294, 1294, 1294, 1294, 1294,
+     1294, 1294, 1294, 1294, 1294, 1296, 1526, 1465, 2095, 2093,
+     1296, 1465,  633,  633,  633,  633,  633,  633,  633,  633,
+      633,  633,  633,  633,  633,  633,  633,  633,  633,  633,
+      633, 1469, 2087, 1548, 1510, 1469, 1465, 1548, 1510, 2086,
+     2083,  633,  633,  639, 1470, 1471, 1481, 1484, 1470, 1471,
+     1481, 1484, 2077, 1469, 1510, 1295, 1295, 1295, 1295, 1295,
+     1295, 1295, 1295, 1295, 1295, 1297, 1470, 1471, 1485, 1484,
+     1297, 2073, 1485, 2054, 2051, 1296, 1296, 1296, 1296, 1296,
+
+     1296, 1296, 1296, 1296, 1296, 1299, 2049, 1488, 2048, 1481,
+     1299, 1488,  639,  639,  639,  639,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  639,  639,  639,  639,  639,
+      639, 1485, 1491, 2047, 1520, 1519, 1491, 1488, 1520, 1519,
+     2046,  639,  639,  645, 1489, 1492, 1511, 1524, 1489, 1492,
+     1511, 1524, 2040, 2039, 1520, 1297, 1297, 1297, 1297, 1297,
+     1297, 1297, 1297, 1297, 1297, 1300, 1511, 1511, 1491, 1523,
+     1300, 1519, 1524, 1523, 2032, 1299, 1299, 1299, 1299, 1299,
+     1299, 1299, 1299, 1299, 1299, 1301, 2000, 1489, 1492, 1999,
+     1301, 1992,  645,  645,  645,  645,  645,  645,  645,  645,
+
+      645,  645,  645,  645,  645,  645,  645,  645,  645,  645,
+      645, 1521, 1523, 1545, 1559, 1521, 1987, 1545, 1559, 1984,
+     1494,  645,  645,  651, 1494, 1514, 1539, 1983, 1976, 1514,
+     1539, 1521, 1521, 1970, 1545, 1300, 1300, 1300, 1300, 1300,
+     1300, 1300, 1300, 1300, 1300, 1303, 1967, 1964, 1525, 1540,
+     1303, 1494, 1525, 1540, 1514, 1301, 1301, 1301, 1301, 1301,
+     1301, 1301, 1301, 1301, 1301, 1304, 1961, 1517, 1539, 1494,
+     1304, 1517,  651,  651,  651,  651,  651,  651,  651,  651,
+      651,  651,  651,  651,  651,  651,  651,  651,  651,  651,
+      651, 1958, 1540, 1955, 1549, 1525, 1527, 1517, 1549, 1953,
+
+     1527,  651,  651,  657, 1528, 1537, 1951, 1551, 1528, 1537,
+     1560, 1551, 1946, 1945, 1560, 1303, 1303, 1303, 1303, 1303,
+     1303, 1303, 1303, 1303, 1303, 1305, 1944, 1527, 1551, 1561,
+     1305, 1549, 1936, 1561, 1537, 1304, 1304, 1304, 1304, 1304,
+     1304, 1304, 1304, 1304, 1304, 1306, 1922, 1916, 1912, 1560,
+     1306, 1528,  657,  657,  657,  657,  657,  657,  657,  657,
+      657,  657,  657,  657,  657,  657,  657,  657,  657,  657,
+      657, 1906, 1561, 1568, 1570, 1533, 1904, 1568, 1570, 1533,
+     1542,  657,  657,  665, 1542, 1546, 1547, 1582, 1562, 1546,
+     1547, 1582, 1562, 1903, 1902, 1305, 1305, 1305, 1305, 1305,
+
+     1305, 1305, 1305, 1305, 1305, 1307, 1533, 1547, 1555, 1542,
+     1307, 1901, 1555, 1546, 1547, 1306, 1306, 1306, 1306, 1306,
+     1306, 1306, 1306, 1306, 1306, 1308, 1891, 1546, 1547, 1555,
+     1308, 1562,  665,  665,  665,  665,  665,  665,  665,  665,
+      665,  665,  665,  665,  665,  665,  665,  665,  665,  665,
+      665, 1558, 1569, 1555, 1576, 1558, 1569, 1890, 1576, 1884,
+     1553,  665,  665,  671, 1553, 1556, 1882, 1583, 1580, 1556,
+     1577, 1583, 1580, 1569, 1577, 1307, 1307, 1307, 1307, 1307,
+     1307, 1307, 1307, 1307, 1307, 1310, 1558, 1576, 1580, 1553,
+     1310, 1875, 1583, 1861, 1556, 1308, 1308, 1308, 1308, 1308,
+
+     1308, 1308, 1308, 1308, 1308, 1311, 1577, 1566, 1857, 1856,
+     1311, 1566,  671,  671,  671,  671,  671,  671,  671,  671,
+      671,  671,  671,  671,  671,  671,  671,  671,  671,  671,
+      671, 1571, 1851, 1581, 1585, 1571, 1566, 1581, 1585, 1848,
+     1567,  671,  671,  677, 1567, 1572, 1571, 1590, 1594, 1572,
+     1846, 1590, 1594, 1581, 1581, 1310, 1310, 1310, 1310, 1310,
+     1310, 1310, 1310, 1310, 1310, 1312, 1845, 1573, 1567, 1595,
+     1312, 1573, 1842, 1595, 1572, 1311, 1311, 1311, 1311, 1311,
+     1311, 1311, 1311, 1311, 1311, 1313, 1841, 1588, 1840, 1829,
+     1313, 1588,  677,  677,  677,  677,  677,  677,  677,  677,
+
+      677,  677,  677,  677,  677,  677,  677,  677,  677,  677,
+      677, 1823, 1821, 1587, 1592, 1573, 1588, 1587, 1592, 1820,
+     1586,  677,  677,  683, 1586, 1819, 1596, 1818, 1817, 1598,
+     1596, 1592, 1592, 1598, 1816, 1312, 1312, 1312, 1312, 1312,
+     1312, 1312, 1312, 1312, 1312, 1315, 1587, 1596, 1586, 1601,
+     1315, 1814, 1811, 1601, 1810, 1313, 1313, 1313, 1313, 1313,
+     1313, 1313, 1313, 1313, 1313, 1316, 1598, 1600, 1802, 1601,
+     1316, 1600,  683,  683,  683,  683,  683,  683,  683,  683,
+      683,  683,  683,  683,  683,  683,  683,  683,  683,  683,
+      683, 1597, 1599, 1604, 1619, 1597, 1599, 1604, 1619, 1780,
+
+     1772,  683,  683,  690, 1600, 1602, 1597, 1615, 1616, 1602,
+     1603, 1615, 1616, 1599, 1603, 1315, 1315, 1315, 1315, 1315,
+     1315, 1315, 1315, 1315, 1315, 1317, 1602, 1602, 1764, 1599,
+     1317, 1763, 1603, 1750, 1743, 1316, 1316, 1316, 1316, 1316,
+     1316, 1316, 1316, 1316, 1316, 1620, 1616, 1691, 1742, 1620,
+     1615, 1691,  690,  690,  690,  690,  690,  690,  690,  690,
+      690,  690,  690,  690,  690,  690,  690,  690,  690,  690,
+      690, 1436, 1606, 1622, 1692, 1436, 1606, 1622, 1692, 1723,
+     1693,  690,  690,  696, 1693, 1720, 1609, 1513, 1620, 1720,
+     1609, 1513, 1436, 1606, 1606, 1317, 1317, 1317, 1317, 1317,
+
+     1317, 1317, 1317, 1317, 1317, 1321, 1436, 1513, 1609, 1613,
+     1721, 1718, 1622, 1613, 1721, 1322, 1755, 1436, 1513, 1767,
+     1755, 1777, 1778, 1767, 1786, 1777, 1778, 1711, 1786, 1695,
+     1613, 1613,  696,  696,  696,  696,  696,  696,  696,  696,
+      696,  696,  696,  696,  696,  696,  696,  696,  696,  696,
+      696, 1621, 1614, 1792, 1793, 1321, 1614, 1792, 1793, 1618,
+     1824,  696,  696,  702, 1824, 1322, 1623, 1578, 1831, 1833,
+     1617, 1578, 1831, 1833, 1614, 1321, 1321, 1321, 1321, 1321,
+     1321, 1321, 1321, 1321, 1321, 1322, 1322, 1322, 1322, 1322,
+     1322, 1322, 1322, 1322, 1322, 1323, 1578, 1578, 1591, 1843,
+
+     1578, 1831, 1578, 1843, 1578, 1324, 1853, 1589, 1584, 1578,
+     1853, 1578,  702,  702,  702,  702,  702,  702,  702,  702,
+      702,  702,  702,  702,  702,  702,  702,  702,  702,  702,
+      702, 1623, 1623, 1623, 1623, 1623, 1623, 1623, 1623, 1623,
+     1623,  702,  702,  708, 1839, 1323, 1908, 1917, 1839, 1932,
+     1908, 1917, 1575, 1932, 1933, 1324, 1844, 1574, 1933, 1935,
+     1844, 1325, 1565, 1935, 1839, 1323, 1323, 1323, 1323, 1323,
+     1323, 1323, 1323, 1323, 1323, 1324, 1324, 1324, 1324, 1324,
+     1324, 1324, 1324, 1324, 1324, 1844, 1995, 1873, 1564, 1563,
+     1995, 1873,  708,  708,  708,  708,  708,  708,  708,  708,
+
+      708,  708,  708,  708,  708,  708,  708,  708,  708,  708,
+      708, 1325, 1873, 2018, 1687, 2019, 2028, 2018, 1687, 2019,
+     2028,  708,  708,  734, 1690, 1722, 1705, 1557, 1690, 1722,
+     1705, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325,
+     1325, 1326, 1687, 1552, 2055, 1690, 1722, 1705, 2055, 2063,
+     1687, 1327, 1550, 2063, 1541, 2064, 1687, 1538, 1687, 2064,
+      734,  734,  734, 1705,  734,  734,  734,  734,  734,  734,
+      734,  734,  734,  734,  734,  734,  734,  734,  734,  734,
+      734,  734,  734,  734,  734,  734,  734,  734,  754, 1697,
+     2066, 1326, 2064, 1697, 2066, 2072, 2091, 1535, 2100, 2072,
+
+     2091, 1327, 2100, 2136, 2150, 2220, 1328, 2136, 2150, 2220,
+     1697, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326,
+     1326, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327,
+     1327, 1697, 1534, 1532, 1531, 1530, 1329,  754,  754,  754,
+      754,  754,  754,  754,  754,  754,  754,  754,  754,  754,
+      754,  754,  754,  754,  754,  754, 1328, 2076, 2097, 2101,
+     2231, 2076, 2097, 2101, 2231, 1529,  754,  754,  760, 1653,
+     2243, 1518, 1515, 1508, 2243, 2231, 1328, 1328, 1328, 1328,
+     1328, 1328, 1328, 1328, 1328, 1328, 1329, 1330, 1507, 1653,
+     1653, 1653, 1653, 1653, 1653, 1653, 1653, 1653, 1653, 1331,
+
+     2101, 2256, 1506, 2097, 2076, 2256, 1329, 1329, 1329, 1329,
+     1329, 1329, 1329, 1329, 1329, 1329, 1624,  760,  760,  760,
+      760,  760,  760,  760,  760,  760,  760,  760,  760,  760,
+      760,  760,  760,  760,  760,  760, 2071, 1330, 2237, 2245,
+     2071, 2267, 2237, 2245, 1504, 2267,  760,  760,  766, 1331,
+     2270, 2273, 1503, 2237, 2270, 2273, 2071, 1330, 1330, 1330,
+     1330, 1330, 1330, 1330, 1330, 1330, 1330, 1332, 2245, 1331,
+     1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1333,
+     1502, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1624,
+     1624, 1625, 1501, 1500, 1499, 2270, 1625,  766,  766,  766,
+
+      766,  766,  766,  766,  766,  766,  766,  766,  766,  766,
+      766,  766,  766,  766,  766,  766, 2074, 1332, 2289, 2291,
+     2074, 2320, 2289, 2291, 1498, 2320,  766,  766,  772, 1333,
+     2328, 2336, 1497, 1496, 2328, 2336, 2074, 1332, 1332, 1332,
+     1332, 1332, 1332, 1332, 1332, 1332, 1332, 1334, 1486, 1333,
+     1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1336,
+     1482, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625,
+     1625, 1626, 1464, 1459, 1441, 1399, 1626,  772,  772,  772,
+      772,  772,  772,  772,  772,  772,  772,  772,  772,  772,
+      772,  772,  772,  772,  772,  772, 2078, 1334, 2364, 2412,
+
+     2078, 2443, 2364, 2412, 1386, 2443,  772,  772,  780, 1336,
+     2448, 2419, 1355, 1351, 2448, 2419, 2078, 1334, 1334, 1334,
+     1334, 1334, 1334, 1334, 1334, 1334, 1334, 1337, 1346, 1336,
+     1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1338,
+     2419, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626,
+     1626, 1627, 1339, 1335, 1314, 1309, 1627,  780,  780,  780,
+      780,  780,  780,  780,  780,  780,  780,  780,  780,  780,
+      780,  780,  780,  780,  780,  780, 2163, 1337, 2454, 2474,
+     2163, 2480, 2454, 2474, 1302, 2480,  780,  780,  788, 1338,
+     2492, 2510, 1298, 1279, 2492, 2510, 2163, 1337, 1337, 1337,
+
+     1337, 1337, 1337, 1337, 1337, 1337, 1337, 1340, 1276, 1338,
+     1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1341,
+     1275, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627,
+     1627, 1628, 1261, 1251, 1249, 1232, 1628,  788,  788,  788,
+      788,  788,  788,  788,  788,  788,  788,  788,  788,  788,
+      788,  788,  788,  788,  788,  788, 2175, 1340, 2516, 2570,
+     2175, 2487, 2516, 2570, 1231, 2487,  788,  788,  796, 1341,
+     2487, 2599, 2487, 1230, 1226, 2599, 2175, 1340, 1340, 1340,
+     1340, 1340, 1340, 1340, 1340, 1340, 1340, 1342, 1199, 1341,
+     1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1343,
+
+     1198, 1628, 1628, 1628, 1628, 1628, 1628, 1628, 1628, 1628,
+     1628, 1629, 1197, 1196, 1195, 1194, 1629,  796,  796,  796,
+      796,  796,  796,  796,  796,  796,  796,  796,  796,  796,
+      796,  796,  796,  796,  796,  796, 2253, 1342, 2642, 2659,
+     2253, 2705, 2642, 2659, 1193, 2705,  796,  796,  802, 1343,
+     2729, 2663, 1182, 1175, 2729, 2663, 2253, 1342, 1342, 1342,
+     1342, 1342, 1342, 1342, 1342, 1342, 1342, 1344, 1174, 1343,
+     1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1345,
+     2663, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629,
+     1629, 1630, 2729, 1172, 1171, 1169, 1630,  802,  802,  802,
+
+      802,  802,  802,  802,  802,  802,  802,  802,  802,  802,
+      802,  802,  802,  802,  802,  802, 2254, 1344, 2730, 2762,
+     2254, 2765, 2730, 2762, 1167, 2765,  802,  802,  808, 1345,
+     2754, 2788, 1153, 1144, 2754, 2788, 2254, 1344, 1344, 1344,
+     1344, 1344, 1344, 1344, 1344, 1344, 1344, 1347, 1137, 1345,
+     1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1348,
+     1132, 1630, 1630, 1630, 1630, 1630, 1630, 1630, 1630, 1630,
+     1630, 1631, 2754, 1092, 1059, 1049, 1631,  808,  808,  808,
+      808,  808,  808,  808,  808,  808,  808,  808,  808,  808,
+      808,  808,  808,  808,  808,  808, 2258, 1347, 2806, 2810,
+
+     2258, 2822, 2806, 2810, 1030, 2822,  808,  808,  818, 1348,
+     2829, 2830,  973,  969, 2829, 2830, 2258, 1347, 1347, 1347,
+     1347, 1347, 1347, 1347, 1347, 1347, 1347, 1349,  963, 1348,
+     1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1350,
+      962, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631,
+     1631, 1632,  961,  960,  959,  958, 1632,  818,  818,  818,
+      818,  818,  818,  818,  818,  818,  818,  818,  818,  818,
+      818,  818,  818,  818,  818,  818, 2329, 1349, 2832, 2833,
+     2329, 2850, 2832, 2833,  923, 2850,  818,  818,  824, 1350,
+     2853, 2871,  922,  891, 2853, 2871, 2329, 1349, 1349, 1349,
+
+     1349, 1349, 1349, 1349, 1349, 1349, 1349, 1352,  886, 1350,
+     1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1353,
+      883, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632,
+     1632, 1633,  871,  816,  794,  786, 1633,  824,  824,  824,
+      824,  824,  824,  824,  824,  824,  824,  824,  824,  824,
+      824,  824,  824,  824,  824,  824, 2337, 1352, 2882, 2892,
+     2337, 2292, 2882, 2892,  737, 2292,  824,  824,  830, 1353,
+     2900,  564,  562,  547, 2900,  546, 2337, 1352, 1352, 1352,
+     1352, 1352, 1352, 1352, 1352, 1352, 1352, 1354,  544, 1353,
+     1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 2292,
+
+      541, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633,
+     1633, 2115, 2116,  539,  537, 2115, 2116,  830,  830,  830,
+      830,  830,  830,  830,  830,  830,  830,  830,  830,  830,
+      830,  830,  830,  830,  830,  830, 2274, 1354, 2116, 2290,
+     2274,  536,  532, 2290, 2115,  531,  830,  830,  839, 1579,
+     1699, 2507, 1702, 1579, 1699, 2507, 1702, 1354, 1354, 1354,
+     1354, 1354, 1354, 1354, 1354, 1354, 1354, 1634,  529, 2274,
+     1579, 1699, 1634, 1702,  524,  523, 2290, 2507, 1579, 1579,
+     1635,  522, 1579,  519, 1579, 1635, 1579,  515,  514,  510,
+     1636, 1579, 1699, 1579, 1702, 1636, 1654,  839,  839,  839,
+
+      839,  839,  839,  839,  839,  839,  839,  839,  839,  839,
+      839,  839,  839,  839,  839,  839, 1654, 1654, 1654, 1654,
+     1654, 1654, 1654, 1654, 1654, 1654,  839,  839,  845, 2399,
+     2381,  509,  507, 2399, 2381,  505,  503, 1634, 1634, 1634,
+     1634, 1634, 1634, 1634, 1634, 1634, 1634, 2381, 2381, 2399,
+     1635, 1635, 1635, 1635, 1635, 1635, 1635, 1635, 1635, 1635,
+     1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636,
+     1637,  502,  501,  500,  498, 1637,  496,  845,  845,  845,
+      845,  845,  845,  845,  845,  845,  845,  845,  845,  845,
+      845,  845,  845,  845,  845,  845, 1708, 1724,  495, 1714,
+
+     1708, 1724,  494, 1714,  491, 1727,  845,  845,  851, 1727,
+     1757, 1760, 2410,  489, 1757, 1760, 2410, 1708, 1724, 1638,
+     1714, 2420,  487, 2391, 1638, 2420, 1727, 2391,  485, 1639,
+      484, 1757, 1760, 1708, 1639,  482, 1714, 2410,  479, 1760,
+     1637, 1637, 1637, 1637, 1637, 1637, 1637, 1637, 1637, 1637,
+     1640, 2391,  477, 1760,  472, 1640, 2420,  851,  851,  851,
+      851,  851,  851,  851,  851,  851,  851,  851,  851,  851,
+      851,  851,  851,  851,  851,  851,  470,  464,  460,  408,
+      385,  376,  327,  177,  174,  166,  851,  851,  857, 1638,
+     1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1639,
+
+     1639, 1639, 1639, 1639, 1639, 1639, 1639, 1639, 1639, 1641,
+      155, 1766, 1775, 1769, 1641, 1766, 1775, 1769,  153,  148,
+     1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640, 1640,
+     1769, 1769, 1766, 1775, 1769,  146,  140,  857,  857,  857,
+      857,  857,  857,  857,  857,  857,  857,  857,  857,  857,
+      857,  857,  857,  857,  857,  857, 1642,  136, 2596, 2387,
+      123, 1642, 2596, 2387,    0,    0,  857,  857,  862, 1696,
+        0, 1746,  862, 1696, 1694, 1746, 2387, 2387, 1694, 1641,
+     1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641, 1641,  862,
+     1643,    0, 1746, 2596, 1783, 1643,    0, 1696, 1783, 1753,
+
+     1794, 1644, 1694, 1753, 1794, 1696, 1644,  862, 1746,    0,
+     1694, 1696, 1694, 1696,    0, 1783, 1783, 1645, 1694,    0,
+     1753, 1794, 1645,    0,    0,    0, 1642, 1642, 1642, 1642,
+     1642, 1642, 1642, 1642, 1642, 1642, 1753,    0,    0,  862,
+      862,  862,  862,  862,  862,  862,  862,  862,  862,  863,
+        0,    0,    0,  863, 2515,    0,    0,    0, 2515,    0,
+     1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643, 1643,
+      863, 1644, 1644, 1644, 1644, 1644, 1644, 1644, 1644, 1644,
+     1644, 1785, 2515,    0,    0, 1785,  863, 1645, 1645, 1645,
+     1645, 1645, 1645, 1645, 1645, 1645, 1645, 1788, 2447,    0,
+
+        0, 1788, 2447, 1785,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0, 2447, 1788,
+      863,  863,  863,  863,  863,  863,  863,  863,  863,  863,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+
+      905,  905,  905,  905,  905,  905,  905,  905,  905,  905,
+      905,  905,  905,  905,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  974,  974,
+      974,  974,  974,  974,  974,  974,  974,  974,  980, 1686,
+
+        0, 1700,  980, 1686,  980, 1700, 1790,    0, 1791, 1791,
+     1790, 1646, 1791, 1826,    0, 2858, 1646, 1826, 1799, 2858,
+     1686, 1647, 1799,    0,    0,    0, 1647, 1686, 1790, 1700,
+     1791, 1648, 2858, 2858, 1826, 1686, 1648, 1700,    0, 1799,
+     1799, 1649,    0, 1686,    0, 1700, 1649,    0, 1700,  980,
+      980,  980,  980,  980,  980,  980,  980,  980,  980,  980,
+      980,  980,  980,  980,  980,  980,  980,  980,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,  980,  980,
+      999, 1646, 1646, 1646, 1646, 1646, 1646, 1646, 1646, 1646,
+     1646, 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1647,
+
+     1647, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,
+     1648, 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1649,
+     1649,  999,  999,  999,  999,  999,  999,  999,  999,  999,
+      999,  999,  999,  999,  999,  999,  999,  999,  999,  999,
+     1081, 1688, 1698, 1812, 1081, 1688, 1698, 1812,    0, 1815,
+     1813, 1822,    0, 1815, 1813, 1822, 1688, 1650,    0, 1701,
+        0, 1081, 1650, 1701, 1703, 1812,    0,    0, 1703, 1688,
+     1698, 1815, 1813, 1822,    0,    0,    0, 1688, 1698, 1813,
+     1822,    0,    0, 1651, 1698, 1688, 1698, 1701, 1651,    0,
+     2498,    0, 1703, 1652, 2498, 1701,    0,    0, 1652,    0,
+
+     1703, 1701, 1741, 1701,    0, 1835, 1741, 1703, 1703, 1835,
+     2498, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081,
+     1081, 1082,    0, 1741,    0, 1082, 1835, 1650, 1650, 1650,
+     1650, 1650, 1650, 1650, 1650, 1650, 1650, 1741,    0,    0,
+        0,    0, 1082,    0,    0, 1704,    0, 1706, 1741, 1704,
+        0, 1706, 1082, 1651, 1651, 1651, 1651, 1651, 1651, 1651,
+     1651, 1651, 1651, 1652, 1652, 1652, 1652, 1652, 1652, 1652,
+     1652, 1652, 1652, 1704,    0, 1706,    0,    0,    0,    0,
+        0, 1704, 1704, 1706,    0,    0,    0,    0,    0, 1704,
+     1706, 1706, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082,
+
+     1082, 1082, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084,
+     1084, 1084, 1084, 1084, 1084, 1084, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088, 1088,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103,
+     1103, 1103, 1103, 1103, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105,
+     1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106,
+     1106, 1106, 1117, 1707,    0, 1709, 1117, 1707, 1117, 1709,
+        0, 1862,    0,    0, 1859, 1862, 1910, 1931, 1859,    0,
+     1910, 1931, 1924,    0, 1949, 1919, 1924,    0, 1949, 1919,
+        0, 1707, 1862, 1709, 1709, 1859, 1859, 1910, 1931, 1707,
+     1707, 1709, 1919, 1919, 1924, 1949, 1919, 1707,    0, 1709,
+        0,    0,    0, 1117, 1117, 1117, 1117, 1117, 1117, 1117,
+     1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117,
+     1117, 1117,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0, 1117, 1117, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
+     1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149,
+     1149, 1149, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151,
+     1151, 1151, 1151, 1151, 1151, 1151, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271,
+     1358, 1710,    0, 1712, 1358, 1710, 1713, 1712, 2541,    0,
+     1713,    0, 2541, 1715, 2002, 1872, 1655, 1715, 2002, 1872,
+     1716, 1358,    0, 1726, 1716,    0,    0, 1726, 2541, 1710,
+     1710, 1712, 1712, 1656, 1713, 2002, 1872, 1710,    0, 1712,
+        0, 1715, 1713, 1713, 1358, 1710, 1657, 1712, 1716, 1715,
+     1713, 1726,    0,    0, 1715,    0, 1716, 1715,    0, 1726,
+
+     1872, 1878,    0, 1658, 1716, 1878, 1655, 1726,    0,    0,
+        0, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
+     1358, 1359, 1878, 1656,    0, 1359, 1655, 1655, 1655, 1655,
+     1655, 1655, 1655, 1655, 1655, 1655, 1657, 2859, 1878,    0,
+        0, 2859, 1359, 1656, 1656, 1656, 1656, 1656, 1656, 1656,
+     1656, 1656, 1656, 1658, 2859, 2859, 1657, 1657, 1657, 1657,
+     1657, 1657, 1657, 1657, 1657, 1657, 1925, 2860, 1926,    0,
+     1925, 2860, 1926, 1658, 1658, 1658, 1658, 1658, 1658, 1658,
+     1658, 1658, 1658,    0, 2860, 2860,    0, 1925, 1925, 1926,
+     1926,    0, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359,
+
+     1359, 1359, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
+     1361, 1361, 1361, 1361, 1361, 1361, 1364, 1717,    0, 1719,
+     1364, 1717, 1364, 1719,    0, 2012,    0, 1979, 1994, 2012,
+
+        0, 1979, 1994,    0, 2022,    0, 2030, 2041, 2022,    0,
+     2030, 2041,    0,    0,    0, 1717, 2012, 1719, 1979, 1994,
+        0,    0, 1719, 1717, 1979, 1719, 2022, 2030,    0, 2041,
+     1717, 1717,    0, 1719, 1994,    0,    0, 1364, 1364, 1364,
+     1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364,
+     1364, 1364, 1364, 1364, 1364, 1364,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0, 1364, 1364, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371,
+     1371, 1371, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402,
+     1402, 1402, 1402, 1402, 1402, 1402, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+     1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419,
+
+     1419, 1419, 1419, 1419, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435,
+     1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474,
+     1474, 1474, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554,
+     1554, 1554, 1554, 1554, 1554, 1554, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+     1659, 1725, 1728, 2586,    0, 1725, 1728, 2586, 1730,    0,
+     1660, 1729, 1730, 1732, 2061, 1729,    0, 1732, 2061,    0,
+     1731, 2043,    0, 2586, 1731, 2043, 1725,    0,    0, 1725,
+     1728,    0,    0,    0, 1730, 2061, 1730, 1725, 1728, 1729,
+     1661, 1732,    0, 2043, 1730, 1725, 1728, 1729, 1731, 1732,
+     1659, 1662, 1730, 1731, 1729, 1729, 1731, 1732,    0,    0,
+
+     1660,    0, 2043,    0, 1731,    0,    0,    0,    0,    0,
+     1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659, 1659,
+     1660, 1660, 1660, 1660, 1660, 1660, 1660, 1660, 1660, 1660,
+     1661, 1663,    0,    0,    0,    0,    0,    0,    0,    0,
+     2781, 1662, 1664, 1736, 2781,    0,    0, 1736,    0,    0,
+     1661, 1661, 1661, 1661, 1661, 1661, 1661, 1661, 1661, 1661,
+     2781, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662,
+     1662, 1736, 1665, 1928, 2045,    0, 1736, 1928, 2045, 1736,
+     2835, 1663, 1666,    0, 2835,    0,    0, 1736,    0, 2053,
+     1928, 1928, 1664, 2053, 1928, 1928, 2045,    0,    0,    0,
+
+     2835, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663, 1663,
+     1663, 2053, 1664, 1664, 1664, 1664, 1664, 1664, 1664, 1664,
+     1664, 1664, 1665, 1667,    0,    0,    0,    0,    0,    0,
+     2053,    0, 1666, 1668, 1744,    0, 1747,    0, 1744,    0,
+     1747,    0, 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1665,
+     1665, 1665, 1666, 1666, 1666, 1666, 1666, 1666, 1666, 1666,
+     1666, 1666, 1744, 1669, 1747, 2094,    0, 2042,    0, 2094,
+     1744, 2042, 1747, 1667, 1670,    0,    0, 1744, 1744,    0,
+     1747,    0,    0, 1668, 2042, 2042, 2094, 1748,    0, 2042,
+        0, 1748,    0, 1667, 1667, 1667, 1667, 1667, 1667, 1667,
+
+     1667, 1667, 1667, 1668, 1668, 1668, 1668, 1668, 1668, 1668,
+     1668, 1668, 1668, 1669, 1671, 1748, 1748,    0,    0,    0,
+        0,    0,    0, 1748, 1670, 1672, 1745,    0,    0,    0,
+     1745, 1748,    0, 1669, 1669, 1669, 1669, 1669, 1669, 1669,
+     1669, 1669, 1669,    0, 1670, 1670, 1670, 1670, 1670, 1670,
+     1670, 1670, 1670, 1670, 1745, 1673, 2052, 2056,    0,    0,
+     2052, 2056, 1745, 1745, 1671, 1674,    0,    0,    0,    0,
+     1745,    0, 2155, 2052, 2052, 1672, 2155, 2056, 2052, 2056,
+        0,    0,    0,    0, 1671, 1671, 1671, 1671, 1671, 1671,
+     1671, 1671, 1671, 1671, 2155, 1672, 1672, 1672, 1672, 1672,
+
+     1672, 1672, 1672, 1672, 1672, 1673, 1675,    0,    0,    0,
+        0,    0,    0,    0,    0, 1674, 1676, 1749,    0, 1751,
+        0, 1749,    0, 1751,    0, 1673, 1673, 1673, 1673, 1673,
+     1673, 1673, 1673, 1673, 1673, 1674, 1674, 1674, 1674, 1674,
+     1674, 1674, 1674, 1674, 1674, 1749, 1677, 1751, 2068,    0,
+     2089,    0, 2068, 1749, 2089, 1751, 1675, 1678,    0,    0,
+     1749, 1749,    0, 1751,    0,    0, 1676,    0, 2068, 2068,
+     1754, 2089, 2089,    0, 1754,    0, 1675, 1675, 1675, 1675,
+     1675, 1675, 1675, 1675, 1675, 1675, 1676, 1676, 1676, 1676,
+     1676, 1676, 1676, 1676, 1676, 1676, 1677, 1679, 1754,    0,
+
+        0,    0,    0,    0,    0,    0, 1754, 1678, 1680, 1752,
+        0,    0,    0, 1752, 1754,    0, 1677, 1677, 1677, 1677,
+     1677, 1677, 1677, 1677, 1677, 1677,    0, 1678, 1678, 1678,
+     1678, 1678, 1678, 1678, 1678, 1678, 1678, 1752, 1681, 2075,
+     2230,    0,    0, 2075, 2230, 1752, 1752, 1679, 1682,    0,
+        0,    0,    0, 1752,    0,    0,    0,    0, 1680, 2075,
+        0, 1756, 2230,    0,    0, 1756,    0, 1679, 1679, 1679,
+     1679, 1679, 1679, 1679, 1679, 1679, 1679, 2075, 1680, 1680,
+     1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1681, 1756,
+        0,    0,    0,    0,    0,    0,    0, 1756, 1682,    0,
+
+        0,    0, 1758,    0,    0, 1756, 1758,    0, 1681, 1681,
+     1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1682, 1682,
+     1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1684, 1737,
+     1758, 1758, 1684, 1737,    0, 1759,    0, 2098, 1758, 1759,
+     1761, 2098,    0,    0, 1761,    0, 1758, 1762,    0, 1684,
+        0, 1762, 1765,    0, 1737,    0, 1765, 1737, 2098,    0,
+     2152,    0,    0, 1759, 2152, 1737, 1684,    0, 1761, 1761,
+        0, 1759,    0, 1737, 2153, 1762, 1761, 1759, 2153, 1759,
+     1765, 2152,    0, 1762, 1761,    0,    0,    0, 1765, 1770,
+     1762, 1762,    0, 1770,    0, 2153, 1765,    0,    0, 1684,
+
+     1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1685,
+     1768, 1770, 1771, 1685, 1768, 1773, 1771, 1770,    0, 1773,
+     2200,    0, 1774,    0, 2200, 1770, 1774, 1768, 1768,    0,
+     1685, 1770, 1776, 1770,    0, 1770, 1776, 1685, 1768,    0,
+     1771, 2200,    0, 1773,    0, 1685, 1768,    0, 1771,    0,
+     1774, 1773,    0, 1685, 1768, 1771, 1771, 2057, 1774, 1773,
+     1776, 2057,    0,    0, 1773,    0, 1774,    0, 1776,    0,
+        0,    0,    0,    0,    0,    0, 1776, 2057, 2057, 2057,
+     1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1685,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689, 1689,
+     1689, 1689, 1689, 1689, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733,
+     1733, 1733, 1733, 1733, 1733, 1733, 1733, 1733, 1738, 1779,
+        0, 1781, 1738, 1779, 1738, 1781,    0, 2218,    0,    0,
+     2173, 2218, 2232,    0, 2173, 2266, 2232, 2238, 2239, 2266,
+     2271, 2238, 2239,    0, 2271,    0,    0, 1779, 2218, 1781,
+     2173, 2173,    0,    0, 2232, 1779, 2266, 1781, 2239, 2238,
+
+     2239, 2271, 1779, 1779,    0, 1781,    0,    0,    0, 1738,
+     1738, 1738, 1738, 1738, 1738, 1738, 1738, 1738, 1738, 1738,
+     1738, 1738, 1738, 1738, 1738, 1738, 1738, 1738, 1782, 2255,
+        0, 2240, 1782, 2255,    0, 2240,    0, 2242, 1738, 1738,
+     2284, 2242, 2287, 2322, 2284,    0, 2287, 2322,    0, 2255,
+     1782, 2240, 2240, 2240,    0,    0, 1782, 2242, 2242, 2242,
+     2255, 2284,    0, 2287, 1782, 2322,    0,    0,    0,    0,
+        0,    0, 1782, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+     1784, 1784, 1784, 1784, 1784, 1784, 1784, 1787, 2323,    0,
+     1795, 1787, 2323, 2338, 1795,    0,    0, 2338,    0, 1797,
+     2383,    0, 1798, 1797, 2383,    0, 1798, 2471,    0, 1787,
+     2323, 2471, 1800,    0, 2338, 1787, 1800,    0, 1795,    0,
+        0, 1803, 2383, 1787, 1798, 1803, 1795, 1797, 2471,    0,
+
+     1798, 1787, 1789, 1789, 1795, 1797, 1789, 1789, 1798, 1789,
+     1800, 2389,    0, 1797, 2471, 2389, 1798, 2440, 1800, 1803,
+     2461, 2440,    0, 1789, 2461,    0, 1800, 1803, 2389, 2389,
+        0,    0, 2473, 2389, 1803, 1803, 2473,    0, 2440,    0,
+        0, 2461,    0,    0,    0,    0,    0, 2440,    0,    0,
+     2461,    0,    0, 2473, 1789, 1789, 1789, 1789, 1789, 1789,
+     1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789,
+     1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789, 1789,
+     1789, 1789, 1789, 1789, 1789, 1801, 1804, 1805,    0, 1801,
+     1804, 1805,    0,    0,    0,    0, 1806, 2446, 1807, 1808,
+
+     1806, 2446, 1807, 1808,    0,    0,    0, 2509, 1825, 1805,
+     1801, 2509, 1825, 1801, 1804, 1805, 1805,    0, 2446, 1804,
+        0, 1801, 1804, 1805, 1806, 1806, 1807, 1808, 2509, 1801,
+     1804, 1805, 1806, 1809, 1807, 1808, 1825, 1809,    0, 1807,
+     1806, 2446, 1807, 1808, 1825, 1827,    0, 1828,    0, 1827,
+     1834, 1828, 1825,    0, 1834, 1809,    0,    0,    0, 1830,
+     1836, 1809, 1809, 1830, 1836, 1827,    0,    0,    0, 1809,
+     1832,    0, 1837, 1827, 1832, 1828, 1837, 1809, 1834,    0,
+     1836, 1827,    0, 1828,    0, 1832, 1834, 1830, 1836, 1827,
+     1828, 1828, 1830, 1838, 1834, 1830, 1836, 1838, 1832,    0,
+
+     1837,    0,    0, 1830, 1836, 1847, 1832, 1849, 1837, 1847,
+        0, 1849,    0,    0, 1832, 1837, 1837,    0, 1852, 1850,
+        0, 1838, 1852, 1850,    0,    0,    0,    0, 1838, 1838,
+     1854,    0,    0, 1847, 1854, 1849, 1849, 1838, 2382,    0,
+        0, 1847, 2382, 1849, 1850,    0, 1852, 1850, 1847, 1847,
+        0, 1849, 1855, 1858, 1852, 1850, 1855, 1858, 1854, 1854,
+     2382,    0, 1852, 1850, 1860, 2388, 1854,    0, 1860, 2388,
+        0,    0, 2486, 1863, 1854, 1858, 2486, 1863, 1864,    0,
+     1855, 1858, 1864,    0, 2382,    0,    0, 2388, 1855, 1858,
+        0,    0, 1860,    0, 2486, 1855, 1855, 1858, 2503, 2538,
+
+     1860, 1863, 2503, 2538,    0,    0, 1864, 1860, 1860, 1863,
+     2486, 2388,    0,    0, 1864, 1863,    0, 1863,    0,    0,
+     2503, 2538, 1864, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865, 1865,
+
+     1865, 1865, 1865, 1865, 1865, 1865, 1865, 1868,    0, 1874,
+     1876, 1868, 1877, 1874, 1876,    0, 1877,    0,    0, 1879,
+     2568, 2690, 1880, 1879, 2568, 2690, 1880,    0,    0, 1881,
+        0,    0, 1868, 1881,    0, 1868,    0, 1874, 1876, 1876,
+     1877, 2568, 2690, 1868,    0, 1874, 1876, 1879, 1877, 1877,
+     1880, 1868, 1874, 1874, 1876, 1879, 1877, 1881, 1880,    0,
+     1885,    0,    0, 1879, 1885, 1881, 1880, 1886, 1881,    0,
+     1887, 1886, 1888, 1881, 1887,    0, 1888, 1889,    0, 1892,
+        0, 1889, 1886, 1892,    0,    0,    0, 2574, 1885, 1893,
+     1894, 2574,    0, 1893, 1894, 1886, 1885, 2490, 1887,    0,
+
+     1888, 2490, 1888, 1886, 1885, 1889, 1887, 1892, 1888, 2574,
+        0, 1886, 1887, 1889, 1887, 1892, 1888, 1893, 1894, 2490,
+     1895, 1889, 1892, 1892, 1895, 1893, 1894, 1896, 2574,    0,
+     1894, 1896, 1897, 1893, 1894, 2490, 1897, 1898, 1899,    0,
+     2590, 1898, 1899,    0, 2590,    0,    0, 2592, 1895, 1900,
+     2621, 2592,    0, 1900, 2621, 1896, 1895,    0,    0,    0,
+     1897, 2590, 2590, 1896, 1895, 1898, 1899, 1899, 1897, 2592,
+     1897, 1896, 2621, 1898, 1899, 1898, 1897, 1900,    0, 1909,
+     1913, 1898, 1899, 1909, 1913, 1900, 1900,    0, 1900,    0,
+     1911, 1914, 2572, 1900, 1911, 1914, 2572, 1915,    0, 2704,
+
+     2619, 1915, 1921, 2704, 2619,    0, 1921, 1909, 1913, 1913,
+        0,    0,    0, 2572,    0, 1909, 1913, 1911, 1911, 1914,
+     2704, 2619,    0, 1909, 1913, 1915, 1911, 1914, 1914, 2572,
+     1921, 1921, 1918, 1915, 1911, 1914, 1918, 2619, 1921, 1920,
+     1915, 1915,    0, 1920, 1923,    0, 1921, 2622, 1923, 1918,
+     1918, 2622,    0,    0,    0,    0,    0,    0, 1929,    0,
+     1918, 1920, 1929,    0,    0,    0,    0, 1920, 1918, 2622,
+     1934,    0, 1923, 1927, 1934, 1920, 1918, 1927, 2724,    0,
+     1923, 1920, 2724, 1920,    0, 1920, 1929, 1923, 1923, 2725,
+     1927, 1927, 2665, 2725, 1929, 1927, 2665,    0, 1934, 2724,
+
+     2724, 1927, 1929,    0,    0, 1934, 1934,    0,    0, 1927,
+        0, 2725, 2665, 2665, 1934,    0,    0, 1927, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+     1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930, 1930,
+
+     1930, 1930, 1937,    0, 1939, 1940, 1937, 1941, 1939, 1940,
+        0, 1941,    0, 2732, 2645,    0, 2764, 2732, 2645, 1943,
+     2764,    0, 2708, 1943, 1942,    0, 2708,    0, 1942,    0,
+     1937,    0, 1939, 1940, 2732, 1941, 2645, 2764, 1937, 1939,
+     1939, 1940, 2645, 1941, 2708, 1941, 1937, 1943, 1939, 1940,
+     1947, 1941, 1942, 1942, 1947, 1943,    0, 1948, 1943,    0,
+     1942, 1948, 1950, 1943, 2708,    0, 1950, 2756, 1942, 1952,
+     2768, 2756,    0, 1952, 2768, 1954,    0,    0, 1947, 1954,
+     2774,    0,    0,    0, 2774, 1948, 1947, 2652,    0, 2756,
+     1950, 2652, 2768, 1948, 1947, 1950, 2783, 1952, 1950, 1948,
+
+     2783, 1948, 2774, 1954,    0, 1952, 1950,    0, 1954, 2652,
+        0, 1954, 1952, 1952,    0, 2652,    0, 2783, 2783, 1954,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+     1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956, 1956,
+
+     1956, 1956, 1956, 1956, 1957, 1959, 1960, 2784, 1957, 1959,
+     1960, 2784,    0,    0, 2715, 1962, 2581, 1963, 2715, 1962,
+     2581, 1963,    0,    0, 1965,    0, 1966, 1968, 1965, 2784,
+     1966, 1968, 1957, 1959, 1960, 1960, 2715, 1957, 2581,    0,
+     1957, 1959, 1960, 1962, 1962, 1963, 1963,    0, 1957, 1959,
+     1960, 1962, 1965, 1963, 1966, 1968, 2715, 2581,    0, 1962,
+     1965, 1963, 1966, 1968, 1968,    0,    0,    0, 1965, 1966,
+     1966, 1968, 1969,    0, 1971, 1972, 1969, 1973, 1971, 1972,
+        0, 1973,    0, 2808, 2817,    0, 1975, 2808, 2817, 1977,
+     1975,    0,    0, 1977, 2828,    0,    0,    0, 2828,    0,
+
+     1969, 1969, 1971, 1972, 2808, 1973, 2817,    0, 1969,    0,
+     1971, 1972, 1971, 1973, 1975, 2828, 1969, 1977, 1971, 1972,
+     1978, 1973, 1975, 1975, 1978, 1977,    0, 1980,    0,    0,
+     1975, 1980, 1977, 1977, 1981,    0,    0, 1982, 1981, 1985,
+     1986, 1982,    0, 1985, 1986, 2849, 1989, 1978, 1978, 2849,
+     1989,    0,    0,    0,    0, 1980, 1978, 2821,    0,    0,
+        0, 2821, 1981, 1980, 1978, 1982, 2849, 1985, 1986, 1986,
+     1981, 1980, 1985, 1982, 1989, 1985, 1986,    0, 1981, 2821,
+        0, 1982, 1989, 1985, 1986, 1988, 1982, 1991,    0, 1988,
+     1989, 1991, 1993,    0, 1996, 2851, 1993, 1997, 1996, 2851,
+
+        0, 1997,    0,    0,    0, 2852, 2001, 1998,    0, 2852,
+     2001, 1998, 1988, 1988,    0, 1991, 1991, 2851,    0,    0,
+     1993, 1988, 1996, 1991,    0, 1997, 2852, 1997, 1993, 1988,
+     1996, 1991, 1998, 1997, 2001, 1998, 1993,    0, 1996,    0,
+     2003, 1997, 2001, 1998, 2003,    0,    0,    0,    0, 2004,
+     2001, 1998, 2005, 2004, 2007,    0, 2005,    0, 2007,    0,
+        0, 2008,    0, 2010,    0, 2008, 2027, 2010, 2003,    0,
+     2027, 2004,    0, 2003,    0, 2029, 2003, 2004,    0, 2029,
+     2005,    0, 2007, 2007, 2003, 2004,    0, 2004, 2005, 2008,
+     2007, 2010,    0, 2004, 2027,    0, 2005, 2008, 2007, 2010,
+
+     2031,    0, 2027, 2029, 2031, 2008,    0, 2010, 2027, 2033,
+     2027, 2029, 2034, 2033,    0,    0, 2034,    0, 2036, 2029,
+     2814,    0, 2036,    0, 2814,    0,    0, 2031, 2031, 2035,
+     2037,    0,    0, 2035, 2037,    0, 2031, 2033,    0, 2038,
+     2034, 2814, 2814, 2038, 2031, 2033, 2036,    0, 2034, 2034,
+     2033, 2035,    0, 2033, 2036, 2037, 2034, 2035, 2037, 2058,
+     2060, 2038, 2036, 2058, 2060, 2035, 2037, 2038,    0,    0,
+     2035,    0, 2062, 2035, 2037, 2038, 2062, 2198, 2065,    0,
+     2038, 2198, 2065, 2038,    0,    0,    0, 2058, 2060,    0,
+     2067,    0,    0,    0, 2067, 2058, 2060, 2069, 2198,    0,
+
+     2062, 2069, 2198, 2058, 2060,    0, 2065, 2070, 2062, 2062,
+     2067, 2070,    0, 2065, 2065,    0, 2062, 2065, 2067, 2079,
+        0, 2198, 2065, 2079, 2065, 2069, 2067, 2070, 2081,    0,
+        0,    0, 2081, 2069, 2067, 2070,    0,    0, 2069,    0,
+     2082, 2069,    0, 2070, 2082, 2070, 2085, 2079,    0, 2084,
+     2085, 2070,    0, 2084,    0, 2079, 2081,    0, 2088,    0,
+        0, 2090, 2088, 2079, 2081, 2090,    0, 2082, 2082,    0,
+        0, 2085, 2081,    0, 2085,    0, 2082, 2084,    0, 2084,
+     2088,    0, 2085, 2092, 2082, 2084, 2088, 2092,    0, 2090,
+     2085,    0, 2096, 2084, 2088,    0, 2096, 2090,    0,    0,
+
+        0,    0, 2088, 2099, 2102, 2090, 2104, 2099, 2102, 2105,
+     2104, 2092,    0, 2105,    0,    0, 2092,    0, 2107, 2092,
+     2096, 2108, 2107,    0,    0, 2108,    0, 2092, 2096,    0,
+        0, 2099, 2102,    0, 2104, 2096, 2096, 2105, 2105, 2099,
+     2102,    0, 2104,    0, 2099, 2105, 2107, 2099, 2102, 2108,
+     2104, 2111, 2112, 2105, 2107, 2111, 2112, 2108,    0,    0,
+        0, 2107, 2107, 2114, 2113, 2108,    0, 2114, 2113,    0,
+     2117,    0,    0, 2118, 2117,    0,    0, 2118,    0, 2111,
+     2112,    0, 2119,    0,    0, 2112, 2119, 2111, 2112, 2114,
+        0, 2114, 2113,    0, 2111, 2111, 2112, 2113, 2117, 2114,
+
+     2113, 2118,    0,    0,    0,    0, 2117, 2114, 2113, 2118,
+     2119, 2120,    0,    0, 2117, 2120, 2121, 2118, 2119, 2119,
+     2121, 2122,    0,    0,    0, 2122, 2119,    0, 2123,    0,
+        0, 2124, 2123, 2717,    0, 2124,    0, 2717,    0, 2120,
+     2120, 2125, 2126,    0, 2121, 2125, 2126, 2120,    0, 2122,
+     2717, 2717, 2121,    0, 2717, 2120, 2123, 2122, 2122, 2124,
+     2121,    0, 2121, 2123, 2123, 2122, 2125, 2124,    0, 2125,
+     2126, 2124, 2123,    0,    0, 2124, 2137, 2125, 2126, 2139,
+     2137, 2126,    0, 2139,    0, 2125, 2126,    0, 2140,    0,
+     2141, 2144, 2140,    0, 2141, 2144,    0, 2143,    0,    0,
+
+        0, 2143,    0,    0, 2137,    0,    0, 2139,    0,    0,
+     2137,    0, 2137, 2144,    0, 2139, 2140, 2140, 2141, 2144,
+     2137,    0,    0, 2139, 2140, 2143, 2141, 2144,    0, 2144,
+     2143,    0, 2140, 2143, 2141, 2144, 2145,    0, 2147, 2148,
+     2145, 2143, 2147, 2148,    0, 2151,    0,    0, 2157, 2151,
+        0,    0, 2157,    0,    0,    0, 2148, 2148,    0, 2154,
+        0,    0,    0, 2154, 2145, 2158, 2147, 2148,    0, 2158,
+        0,    0, 2145, 2151, 2147, 2148, 2157,    0,    0, 2145,
+     2145, 2151, 2147, 2148, 2157,    0, 2147, 2154,    0, 2151,
+     2159,    0, 2157, 2158, 2159, 2154, 2719, 2154, 2721,    0,
+
+     2719, 2158, 2721, 2154,    0,    0,    0, 2158,    0, 2158,
+        0,    0,    0, 2719, 2719, 2721, 2721, 2719, 2159, 2721,
+        0,    0,    0,    0,    0,    0, 2159,    0,    0,    0,
+        0,    0,    0,    0, 2159,    0, 2159, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160,
+     2160, 2164, 2165, 2167, 2169, 2164, 2165, 2167, 2169,    0,
+        0,    0,    0, 2171,    0,    0,    0, 2171,    0,    0,
+        0,    0, 2180,    0,    0,    0, 2180,    0, 2167, 2164,
+     2165, 2167, 2169,    0,    0, 2169,    0, 2164, 2165, 2167,
+     2169, 2171,    0, 2165, 2164, 2164, 2165, 2167, 2169, 2171,
+     2180, 2182, 2184, 2180,    0, 2182, 2184, 2171, 2180,    0,
+        0, 2185,    0, 2187,    0, 2185, 2180, 2187,    0,    0,
+        0,    0, 2190, 2189, 2192,    0, 2190, 2189, 2192, 2182,
+
+     2184,    0,    0,    0,    0,    0, 2193, 2182, 2184, 2185,
+     2193, 2187,    0,    0, 2182, 2182, 2184, 2185, 2189, 2187,
+     2190, 2189, 2192,    0, 2185, 2185,    0, 2187, 2190, 2189,
+     2192,    0,    0,    0, 2193, 2190, 2190, 2189, 2192, 2193,
+     2194,    0, 2193, 2195, 2194, 2197,    0, 2195,    0, 2197,
+     2193,    0, 2199,    0, 2201,    0, 2199, 2204, 2201,    0,
+        0, 2204,    0, 2206,    0,    0,    0, 2206, 2194, 2194,
+     2197, 2195,    0, 2197, 2207,    0, 2194,    0, 2207, 2195,
+     2199, 2197, 2201, 2201, 2194, 2204,    0, 2195, 2199, 2197,
+     2201, 2206,    0, 2204,    0,    0, 2199,    0, 2201, 2206,
+
+     2204, 2204, 2207,    0, 2209, 2211, 2206, 2206, 2209, 2211,
+     2207,    0,    0,    0,    0, 2212, 2215, 2207, 2207, 2212,
+     2215,    0, 2217,    0,    0,    0, 2217,    0,    0, 2209,
+        0,    0, 2209, 2211,    0, 2216,    0,    0, 2211, 2216,
+     2209, 2211, 2212, 2212, 2215,    0,    0,    0, 2209, 2211,
+     2217, 2212, 2215,    0,    0,    0,    0, 2216, 2217, 2212,
+     2215, 2219,    0, 2216, 2221, 2219, 2217,    0, 2221,    0,
+        0, 2216,    0, 2223, 2224,    0, 2216, 2223, 2224, 2216,
+        0,    0,    0, 2226, 2225,    0, 2241, 2226, 2225, 2219,
+     2241,    0, 2221,    0,    0,    0,    0, 2219, 2221, 2225,
+
+     2221, 2223, 2224, 2224,    0, 2219, 2223,    0, 2221, 2223,
+     2224, 2226, 2225,    0, 2241,    0,    0, 2223, 2224, 2226,
+     2225, 2227, 2241,    0,    0, 2227,    0, 2226, 2225,    0,
+     2241, 2244,    0, 2246,    0, 2244, 2227, 2246, 2247,    0,
+     2248,    0, 2247,    0, 2248,    0,    0,    0,    0, 2227,
+     2249,    0,    0,    0, 2249,    0,    0, 2227,    0, 2244,
+     2244, 2246,    0, 2247,    0, 2227, 2247, 2244, 2248, 2246,
+        0, 2246,    0,    0, 2247, 2244, 2248, 2246, 2249, 2248,
+        0, 2250, 2247,    0, 2248, 2250, 2249, 2251, 2249,    0,
+        0, 2251, 2259,    0, 2249,    0, 2259,    0,    0, 2261,
+
+        0,    0, 2262, 2261,    0,    0, 2262, 2251,    0, 2250,
+        0,    0, 2265,    0, 2250, 2251, 2265, 2250, 2251,    0,
+     2259,    0,    0, 2251,    0, 2250, 2259, 2261, 2259, 2262,
+     2262, 2251, 2261, 2268,    0, 2261, 2259, 2268, 2262,    0,
+     2265,    0,    0, 2261,    0, 2269, 2262, 2272, 2265, 2269,
+     2275, 2272,    0,    0, 2275,    0, 2265,    0, 2268, 2277,
+     2269, 2268, 2278, 2277,    0,    0, 2278,    0, 2281, 2268,
+        0,    0, 2281, 2269,    0, 2272,    0, 2268, 2275,    0,
+     2272, 2269,    0, 2272,    0,    0, 2275, 2277, 2282, 2269,
+     2278, 2272, 2282, 2275, 2275, 2277, 2281, 2281, 2278,    0,
+
+        0,    0,    0, 2277, 2281, 2278, 2278, 2283,    0,    0,
+     2285, 2283, 2281, 2286, 2285,    0, 2282, 2286,    0,    0,
+        0,    0, 2288,    0, 2282, 2293, 2288,    0,    0, 2293,
+        0,    0, 2282,    0,    0, 2283,    0, 2282, 2285,    0,
+        0, 2286,    0, 2283, 2294,    0, 2285, 2285, 2294, 2286,
+     2288, 2283,    0, 2293, 2285, 2295,    0, 2286, 2288, 2295,
+     2288, 2293,    0,    0,    0,    0, 2288, 2296, 2293, 2293,
+        0, 2296, 2294,    0,    0,    0,    0, 2294,    0,    0,
+     2294, 2297, 2295, 2295,    0, 2297, 2298,    0, 2294,    0,
+     2298, 2295, 2299, 2300,    0, 2296, 2299, 2300, 2301, 2295,
+
+        0, 2298, 2301, 2296, 2296,    0,    0,    0,    0, 2297,
+     2297, 2296, 2302,    0, 2298, 2312, 2302, 2297,    0, 2312,
+     2299, 2300, 2298,    0,    0, 2297, 2301, 2299, 2299, 2300,
+     2298,    0,    0,    0, 2301, 2314, 2299, 2300,    0, 2314,
+     2302, 2302, 2301, 2312,    0, 2315, 2316,    0, 2302, 2315,
+     2316, 2312,    0,    0,    0,    0, 2302, 2318, 2317, 2312,
+     2321, 2318, 2317, 2314, 2321,    0,    0,    0,    0,    0,
+        0, 2314, 2325, 2315, 2316,    0, 2325,    0,    0, 2314,
+     2317, 2315, 2316, 2326,    0, 2318, 2317, 2326, 2321, 2315,
+     2316, 2321,    0, 2318, 2317,    0, 2321,    0,    0, 2317,
+
+     2325, 2318, 2317, 2330, 2321, 2332, 2334, 2330, 2325, 2332,
+     2334, 2326,    0,    0, 2325,    0, 2325, 2339, 2341, 2326,
+     2343, 2339, 2341,    0, 2343,    0,    0, 2326, 2330,    0,
+        0, 2330, 2332, 2332, 2334,    0,    0,    0,    0, 2330,
+     2345, 2332, 2334,    0, 2345, 2339, 2341, 2330, 2343, 2332,
+     2334, 2346,    0, 2339, 2341, 2346, 2343,    0,    0,    0,
+        0, 2339, 2341, 2348, 2343, 2349, 2350, 2348, 2345, 2349,
+     2350,    0,    0,    0,    0,    0, 2345,    0,    0, 2346,
+        0,    0,    0, 2345, 2345,    0,    0, 2346, 2351,    0,
+        0, 2348, 2351, 2349, 2350, 2346,    0,    0,    0, 2348,
+
+     2353, 2349, 2350,    0, 2353,    0,    0, 2348,    0, 2349,
+     2350, 2354,    0, 2351, 2349, 2354, 2351, 2357, 2360,    0,
+        0, 2357, 2360, 2362, 2351,    0,    0, 2362, 2353, 2363,
+        0,    0, 2351, 2363,    0,    0, 2353,    0, 2367, 2354,
+        0,    0, 2367,    0, 2353, 2357, 2360, 2354, 2354,    0,
+        0, 2362, 2365, 2357, 2360, 2354, 2365, 2363,    0, 2362,
+        0, 2357, 2360,    0, 2368, 2363, 2367, 2362, 2368,    0,
+        0,    0,    0, 2363, 2367, 2367,    0, 2371,    0, 2365,
+     2365, 2371, 2367,    0,    0,    0, 2373, 2372, 2365, 2375,
+     2373, 2372, 2368, 2375,    0,    0, 2365,    0, 2368, 2376,
+
+     2368,    0,    0, 2376,    0, 2371, 2371,    0, 2368, 2372,
+        0,    0, 2377, 2371, 2373, 2372, 2377, 2375,    0,    0,
+        0, 2371, 2373, 2372, 2378, 2375,    0, 2376, 2378,    0,
+     2373, 2372,    0, 2375, 2377, 2376, 2375, 2390, 2392,    0,
+     2377, 2390, 2392, 2376,    0,    0, 2378, 2393, 2377, 2394,
+     2396, 2393, 2378, 2394, 2396,    0, 2377,    0, 2377, 2395,
+     2378,    0,    0, 2395,    0, 2390, 2392,    0, 2378,    0,
+     2378,    0,    0, 2390, 2392, 2393,    0, 2394, 2396,    0,
+     2393, 2390, 2392, 2393, 2392, 2394, 2396, 2395, 2394,    0,
+        0, 2393, 2397, 2394, 2396, 2395, 2397, 2396, 2401,    0,
+
+     2395, 2403, 2401, 2395, 2407, 2403,    0, 2404, 2407,    0,
+        0, 2404, 2397,    0,    0,    0,    0,    0, 2408, 2409,
+     2397, 2411, 2408, 2409,    0, 2411, 2401,    0, 2397, 2403,
+        0,    0, 2407,    0, 2401, 2404, 2397, 2403, 2403, 2407,
+     2407, 2404, 2401, 2404, 2409, 2403, 2408, 2409, 2407, 2411,
+        0, 2404, 2413,    0, 2408, 2409, 2413, 2411,    0,    0,
+     2408,    0, 2408, 2409, 2415, 2411, 2416,    0, 2415, 2417,
+     2416, 2418,    0, 2417,    0, 2418,    0,    0,    0,    0,
+     2413,    0,    0,    0,    0,    0, 2422,    0, 2413, 2421,
+     2422,    0, 2415, 2421, 2416, 2416, 2413, 2417, 2417, 2418,
+
+     2415,    0, 2416,    0,    0, 2417, 2418, 2418, 2415,    0,
+     2416, 2415, 2423, 2417, 2422, 2418, 2423, 2421, 2421,    0,
+        0,    0, 2422, 2424, 2425, 2421,    0, 2424, 2425,    0,
+     2422, 2422,    0, 2421, 2426,    0,    0,    0, 2426,    0,
+     2423,    0,    0,    0,    0, 2427,    0,    0, 2423, 2427,
+        0, 2424, 2425,    0, 2428, 2423, 2423, 2439, 2428, 2424,
+     2425, 2439, 2426,    0,    0, 2425, 2424, 2424, 2425,    0,
+     2426, 2426, 2429, 2427, 2427, 2441, 2429,    0, 2426, 2441,
+     2428, 2427, 2428,    0, 2442, 2439,    0, 2439, 2442, 2427,
+     2428,    0,    0, 2439,    0, 2444,    0,    0, 2428, 2444,
+
+     2429, 2439,    0, 2441, 2441, 2445, 2442,    0, 2429, 2445,
+     2449, 2441, 2442, 2429, 2449,    0, 2429, 2450,    0, 2441,
+     2442, 2450, 2452, 2444,    0,    0, 2452,    0, 2442,    0,
+        0, 2444, 2455, 2445,    0,    0, 2455, 2449, 2449, 2444,
+        0, 2445,    0,    0, 2457, 2450, 2449, 2452, 2457, 2445,
+     2452, 2450,    0, 2450, 2449, 2458,    0, 2455, 2452, 2458,
+     2455, 2450,    0,    0,    0, 2459, 2452, 2460, 2455, 2459,
+     2462, 2460, 2457, 2457, 2462,    0, 2455,    0,    0,    0,
+     2457,    0, 2458, 2458,    0,    0,    0,    0, 2457,    0,
+        0, 2458, 2464, 2459, 2459, 2460, 2464, 2460, 2462, 2458,
+
+        0, 2459,    0, 2460, 2465,    0, 2462,    0, 2465, 2459,
+        0, 2460,    0, 2462, 2462, 2470,    0, 2472, 2464, 2470,
+     2464, 2472, 2475,    0,    0,    0, 2475, 2477, 2464, 2465,
+        0, 2477, 2465,    0, 2478,    0, 2464, 2481, 2478,    0,
+     2465, 2481,    0, 2470,    0, 2472,    0,    0, 2465,    0,
+     2475, 2470, 2470, 2472, 2475, 2477, 2477,    0, 2475, 2470,
+     2482, 2472, 2478, 2477, 2482, 2481, 2475,    0,    0,    0,
+     2478, 2477, 2483, 2481,    0, 2491, 2483,    0, 2478, 2491,
+        0, 2481, 2482,    0,    0, 2493,    0, 2494, 2482, 2493,
+        0, 2494,    0,    0, 2496,    0, 2482, 2495, 2496,    0,
+
+     2483, 2495, 2482, 2491, 2482,    0, 2500,    0, 2483,    0,
+     2500, 2491,    0, 2493, 2493, 2494, 2483,    0,    0, 2491,
+     2504, 2493, 2496, 2494, 2504, 2495, 2495,    0, 2494, 2493,
+     2496, 2494, 2501, 2495, 2500, 2500, 2501,    0, 2496, 2505,
+        0, 2495, 2500, 2505,    0, 2506,    0,    0, 2504, 2506,
+     2500, 2508,    0, 2504, 2501, 2508, 2504, 2511, 2512,    0,
+     2501, 2511, 2512,    0, 2504,    0,    0, 2505, 2501,    0,
+     2513, 2506,    0, 2506, 2513, 2505, 2501,    0,    0, 2508,
+     2514, 2506, 2505, 2505, 2514, 2511, 2512, 2508,    0, 2506,
+        0,    0, 2517, 2511, 2512, 2508, 2517,    0, 2513, 2519,
+
+     2511, 2511, 2512, 2519,    0, 2518, 2513,    0, 2514, 2518,
+        0, 2520,    0,    0, 2513, 2520, 2514, 2522,    0,    0,
+     2517, 2522, 2521,    0, 2514,    0, 2521, 2519, 2517,    0,
+     2518,    0, 2519, 2518, 2523, 2519, 2517, 2521, 2523, 2520,
+        0, 2518,    0, 2519, 2520, 2522,    0, 2520, 2524, 2518,
+     2521,    0, 2524, 2522,    0, 2520,    0,    0, 2521, 2525,
+     2536, 2522, 2523, 2525, 2536, 2534, 2521,    0,    0, 2534,
+     2523, 2523,    0,    0, 2525,    0, 2524,    0, 2523,    0,
+        0, 2524,    0,    0, 2524, 2537, 2539, 2525, 2536, 2537,
+     2539,    0, 2524, 2534,    0, 2525, 2536,    0, 2542,    0,
+
+     2534, 2534, 2542, 2525, 2536,    0,    0, 2537, 2543, 2534,
+        0, 2545, 2543, 2537, 2539, 2545,    0,    0,    0,    0,
+     2547, 2537, 2539,    0, 2547, 2539, 2542, 2537,    0, 2537,
+     2539, 2549, 2542, 2550, 2542, 2549, 2543, 2550,    0, 2545,
+        0,    0, 2542,    0, 2543, 2551,    0, 2545, 2547, 2551,
+     2552,    0, 2543,    0, 2552, 2545, 2547,    0,    0, 2549,
+        0, 2550, 2554,    0, 2547,    0, 2554, 2549, 2556, 2550,
+        0,    0, 2556, 2551,    0, 2549, 2550, 2550, 2552, 2557,
+     2562, 2551,    0, 2557, 2562, 2552, 2552,    0,    0, 2551,
+     2554, 2566,    0, 2564, 2552, 2566, 2556, 2564, 2554,    0,
+
+        0, 2556,    0, 2554, 2556,    0, 2554, 2557, 2562, 2562,
+     2567,    0, 2556, 2571, 2567, 2557, 2562, 2571,    0, 2566,
+        0, 2564,    0, 2557, 2562,    0, 2564, 2566, 2582, 2564,
+     2573,    0, 2582,    0, 2573, 2566,    0, 2564, 2567, 2583,
+     2585, 2571,    0, 2583, 2585,    0, 2567,    0,    0, 2571,
+     2571, 2584, 2573,    0, 2567, 2584, 2582, 2571, 2573,    0,
+        0, 2588,    0,    0, 2582, 2588, 2573, 2583, 2585, 2582,
+        0,    0, 2582,    0, 2573, 2583, 2585,    0,    0, 2584,
+        0, 2583, 2585, 2583, 2585,    0, 2589, 2584,    0, 2588,
+     2589,    0, 2584,    0,    0, 2584, 2593, 2588, 2594, 2597,
+
+     2593,    0, 2594, 2597,    0, 2588,    0,    0, 2589,    0,
+        0,    0,    0, 2595, 2589,    0, 2598, 2595,    0, 2597,
+     2598,    0, 2589,    0, 2593,    0, 2594, 2597,    0,    0,
+     2589,    0, 2593, 2600, 2594, 2597,    0, 2600,    0, 2594,
+     2593, 2595, 2594, 2597, 2598, 2593, 2601,    0, 2595, 2595,
+     2601, 2602, 2598,    0,    0, 2602,    0, 2595,    0,    0,
+     2598, 2600,    0, 2603,    0,    0,    0, 2603, 2600, 2600,
+        0,    0,    0,    0, 2601,    0, 2604, 2600,    0, 2602,
+     2604, 2605, 2601,    0, 2601, 2605,    0, 2602,    0,    0,
+     2601, 2603,    0,    0, 2602, 2602,    0,    0, 2606, 2603,
+
+        0,    0, 2606,    0, 2604,    0,    0, 2603,    0, 2605,
+     2607, 2604, 2604,    0, 2607, 2616,    0, 2605,    0, 2616,
+     2604,    0,    0,    0, 2605, 2605, 2606, 2618,    0, 2606,
+        0, 2618,    0,    0, 2606,    0,    0, 2623, 2607,    0,
+     2616, 2623, 2606, 2616, 2620,    0, 2607,    0, 2620, 2625,
+        0, 2616,    0, 2625, 2607, 2618, 2626,    0, 2627, 2616,
+     2626,    0, 2627, 2618, 2618, 2623, 2620,    0,    0,    0,
+     2629, 2618, 2620, 2623, 2629,    0, 2623, 2625,    0,    0,
+     2620, 2623,    0, 2627, 2626, 2625, 2627, 2631, 2620,    0,
+        0, 2631, 2626, 2625, 2627,    0,    0,    0, 2629,    0,
+
+     2626, 2632, 2627, 2629, 2637, 2632, 2629, 2639, 2637,    0,
+        0, 2639,    0, 2641, 2629, 2631,    0, 2641, 2631,    0,
+        0,    0, 2653, 2631, 2643,    0, 2653, 2632, 2643, 2632,
+        0, 2631, 2637,    0, 2654, 2639,    0, 2632, 2654,    0,
+     2637, 2641,    0, 2639, 2639, 2632,    0, 2637, 2637, 2641,
+     2653, 2639, 2643, 2643,    0, 2655,    0, 2641, 2653, 2655,
+     2643, 2656, 2654,    0,    0, 2656, 2653, 2658, 2643,    0,
+     2654, 2658, 2660,    0,    0,    0, 2660,    0, 2654,    0,
+        0, 2661, 2664, 2655, 2662, 2661, 2664,    0, 2662, 2656,
+        0, 2655,    0,    0, 2666, 2658,    0, 2656, 2666, 2655,
+
+     2660, 2660, 2664, 2658,    0, 2656,    0,    0, 2660, 2661,
+     2664, 2658, 2662, 2662, 2661, 2667, 2660, 2661, 2664, 2667,
+     2662,    0, 2666,    0,    0, 2661, 2664, 2668, 2662, 2669,
+     2666, 2668, 2670, 2669,    0,    0, 2670,    0, 2666,    0,
+        0,    0,    0, 2667, 2667,    0, 2671,    0,    0,    0,
+     2671, 2667, 2672,    0,    0, 2668, 2672, 2669, 2673, 2667,
+     2670,    0, 2673, 2668, 2668, 2669,    0,    0, 2670, 2670,
+        0, 2668,    0, 2669, 2671, 2674, 2670, 2669,    0, 2674,
+     2672, 2671, 2671,    0,    0, 2672, 2673, 2683, 2672,    0,
+     2671, 2683,    0, 2685, 2673,    0, 2672, 2685,    0,    0,
+
+        0,    0, 2673, 2674, 2687,    0, 2689,    0, 2687,    0,
+     2689, 2674, 2674, 2691,    0, 2683,    0, 2691, 2683, 2674,
+        0, 2685, 2685, 2683, 2693,    0, 2695,    0, 2693, 2685,
+     2695, 2683, 2687, 2687, 2689,    0,    0, 2685,    0, 2696,
+     2687, 2691, 2689, 2696, 2691,    0,    0,    0, 2687, 2691,
+     2689, 2699, 2693,    0, 2695, 2699,    0, 2691,    0,    0,
+     2693, 2701, 2695,    0,    0, 2701,    0, 2696, 2693,    0,
+     2695, 2693, 2696, 2703, 2716, 2696, 2706, 2703, 2716, 2699,
+     2706,    0,    0, 2696,    0,    0,    0, 2699,    0, 2701,
+     2701, 2716, 2716,    0, 2723, 2699, 2718, 2701, 2723, 2726,
+
+     2718, 2703, 2716, 2726, 2706, 2701,    0,    0,    0, 2703,
+     2716, 2720, 2706, 2718, 2718, 2720, 2723, 2703, 2716, 2706,
+     2706, 2727, 2723,    0, 2718, 2727,    0, 2726, 2720, 2720,
+     2723,    0, 2718, 2728,    0, 2726,    0, 2728, 2723, 2720,
+     2718,    0, 2731, 2726, 2733,    0, 2731, 2720, 2733, 2727,
+        0,    0,    0,    0,    0, 2720,    0, 2727, 2727, 2734,
+        0, 2728,    0, 2734, 2735, 2727,    0,    0, 2735, 2728,
+     2731,    0, 2733,    0,    0, 2728,    0, 2728, 2731, 2736,
+     2733, 2733,    0, 2736, 2734,    0, 2731, 2734, 2733, 2737,
+        0,    0, 2735, 2737,    0, 2734,    0, 2735, 2738,    0,
+
+     2735, 2747, 2738, 2734, 2736, 2747,    0, 2736, 2735,    0,
+     2749,    0,    0,    0, 2749, 2736, 2747, 2737,    0,    0,
+     2751,    0,    0, 2736, 2751, 2737, 2738, 2737,    0, 2747,
+        0, 2738, 2753, 2737, 2738,    0, 2753, 2747, 2749,    0,
+        0,    0, 2738,    0,    0, 2747, 2749,    0, 2751,    0,
+        0,    0,    0, 2749, 2749,    0, 2751,    0,    0,    0,
+     2753, 2751,    0,    0, 2751,    0,    0,    0, 2753,    0,
+        0,    0,    0,    0, 2753,    0, 2753, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755, 2755,
+     2755, 2757, 2758,    0, 2761, 2757, 2758, 2763, 2761,    0,
+        0, 2763,    0, 2766,    0,    0,    0, 2766,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0, 2757,
+     2758,    0, 2761, 2758,    0, 2763,    0, 2757, 2758, 2757,
+
+     2761, 2766,    0, 2763,    0, 2757, 2758,    0, 2761, 2766,
+     2775, 2763, 2777,    0, 2775, 2779, 2777, 2766,    0, 2779,
+        0, 2785, 2782,    0,    0, 2785, 2782, 2775, 2775, 2777,
+     2777,    0, 2779, 2779,    0, 2786,    0,    0, 2775, 2786,
+     2777, 2789,    0, 2779, 2782, 2789, 2775,    0, 2777, 2785,
+     2782, 2779, 2785,    0, 2775,    0, 2777, 2785, 2782, 2779,
+     2790,    0,    0, 2786, 2790, 2785, 2782,    0,    0, 2789,
+     2791, 2786, 2792,    0, 2791,    0, 2792, 2789,    0, 2786,
+        0,    0, 2793, 2794, 2789, 2789, 2793, 2794, 2790, 2801,
+        0,    0,    0, 2801,    0, 2790, 2790,    0, 2791,    0,
+
+     2792, 2803,    0,    0, 2790, 2803, 2791, 2792, 2792,    0,
+     2793, 2794,    0,    0, 2791, 2791, 2792, 2801, 2793, 2794,
+     2805,    0,    0,    0, 2805, 2801, 2793, 2794, 2794, 2803,
+     2807, 2809, 2812, 2801, 2807, 2809, 2812, 2803,    0,    0,
+        0,    0, 2823, 2824,    0, 2803, 2823, 2824, 2805, 2827,
+        0,    0,    0, 2827,    0,    0, 2805,    0, 2807, 2809,
+     2812,    0,    0,    0, 2805,    0, 2807, 2809, 2812, 2836,
+     2823, 2824,    0, 2836, 2807, 2809, 2812, 2827, 2823, 2824,
+        0,    0,    0,    0, 2836, 2827, 2823, 2824, 2837,    0,
+        0, 2838, 2837, 2827, 2839, 2838,    0, 2836, 2839,    0,
+
+        0,    0,    0, 2846,    0, 2836, 2848, 2846,    0,    0,
+     2848,    0,    0, 2836,    0,    0, 2837, 2837,    0, 2838,
+        0, 2854, 2839, 2839, 2837, 2854,    0, 2838,    0,    0,
+     2839, 2846, 2837, 2838, 2848, 2838, 2846,    0, 2839, 2846,
+     2855, 2862, 2848,    0, 2855, 2862,    0, 2846,    0, 2854,
+     2848, 2863, 2864,    0,    0, 2863, 2864, 2854,    0,    0,
+        0,    0, 2870, 2854,    0, 2854, 2870,    0, 2855, 2862,
+        0,    0,    0,    0,    0,    0, 2855, 2862, 2855, 2863,
+     2864,    0, 2868, 2862, 2855, 2862, 2868, 2863, 2864, 2874,
+     2870,    0, 2863, 2874, 2864, 2863, 2864,    0, 2870, 2875,
+
+        0,    0,    0, 2875, 2876,    0, 2870, 2868, 2876, 2879,
+     2868,    0,    0, 2879,    0,    0, 2881, 2874, 2868, 2885,
+     2881,    0, 2874, 2885,    0, 2874, 2868, 2875,    0, 2876,
+        0,    0, 2876, 2874, 2886, 2875, 2879, 2879, 2886,    0,
+     2876, 2875,    0, 2875, 2881, 2879, 2887, 2885, 2876,    0,
+     2887,    0, 2881, 2879,    0, 2885,    0, 2890, 2881, 2886,
+     2881, 2890, 2886, 2885,    0,    0,    0, 2894, 2885, 2895,
+     2886, 2894,    0, 2895, 2887,    0,    0,    0, 2886, 2898,
+        0, 2887, 2887, 2898,    0, 2890,    0,    0, 2903,    0,
+     2887,    0, 2903, 2890,    0, 2894, 2894, 2895, 2890,    0,
+
+        0, 2890, 2906, 2894, 2895, 2895, 2906, 2898,    0,    0,
+        0, 2894, 2898, 2895, 2909, 2898, 2903, 2912, 2909,    0,
+        0, 2912,    0, 2898, 2903,    0,    0,    0,    0,    0,
+     2906, 2903, 2903,    0,    0, 2906,    0,    0, 2906,    0,
+        0, 2909, 2909,    0,    0, 2912, 2906,    0,    0,    0,
+     2909,    0,    0, 2912,    0,    0,    0,    0, 2909, 2912,
+        0, 2912, 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
+     2916, 2916, 2916, 2916, 2916, 2917, 2917, 2917, 2917, 2917,
+     2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2918, 2918,
+     2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
+
+     2918, 2919, 2919, 2919, 2919, 2919, 2919, 2919, 2919, 2919,
+     2919, 2919, 2919, 2919, 2920, 2920, 2920, 2920, 2920, 2920,
+     2920, 2920, 2920, 2920, 2920, 2920, 2920, 2921, 2921, 2921,
+     2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+     2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+     2922, 2922, 2922, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+     2923, 2923, 2923, 2923, 2923, 2923, 2924, 2924, 2924, 2924,
+     2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2925,
+     2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925,
+     2925, 2925, 2926, 2926, 2926, 2926, 2926, 2926, 2926, 2926,
+
+     2926, 2926, 2926, 2926, 2926, 2927, 2927, 2927, 2927, 2927,
+     2927, 2927, 2927, 2927, 2927, 2927, 2927, 2927, 2928, 2928,
+     2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+     2928, 2929, 2929,    0, 2929, 2929, 2929, 2929, 2929, 2929,
+     2929, 2929, 2929, 2929, 2930, 2930, 2930, 2930, 2930,    0,
+     2930, 2930, 2930, 2930, 2931, 2931,    0, 2931, 2931, 2931,
+     2931, 2931, 2931, 2931, 2931, 2931, 2931, 2932, 2932,    0,
+     2932, 2932, 2932, 2932, 2932, 2932, 2932, 2932, 2932, 2932,
+     2933, 2933, 2933, 2933, 2933, 2933, 2933, 2933, 2933, 2933,
+     2934, 2934,    0, 2934, 2934, 2934, 2934, 2934, 2934, 2934,
+
+     2934, 2934, 2934, 2935, 2935,    0, 2935, 2935, 2935, 2935,
+     2935, 2935, 2935, 2935, 2935, 2935, 2936, 2936,    0, 2936,
+     2936, 2936, 2936, 2936, 2936, 2936, 2936, 2936, 2936, 2937,
+        0, 2937, 2937,    0, 2937, 2937, 2937, 2937, 2937, 2937,
+     2937, 2937, 2938, 2938,    0,    0, 2938, 2938, 2938, 2938,
+     2938, 2938, 2939, 2939,    0, 2939, 2939, 2939, 2939, 2939,
+     2939, 2939, 2939, 2939, 2939, 2940, 2940,    0, 2940, 2940,
+     2940, 2940, 2940, 2940, 2940, 2940, 2940, 2940, 2941, 2941,
+        0,    0, 2941, 2941, 2941, 2941, 2941, 2941, 2942, 2942,
+        0, 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+
+     2942, 2943, 2943,    0, 2943, 2943, 2943, 2943, 2943, 2943,
+     2943, 2943, 2943, 2943, 2944, 2944, 2944, 2944, 2944, 2944,
+     2944, 2944,    0, 2944, 2944, 2944, 2944, 2945, 2945,    0,
+        0, 2945, 2945, 2945, 2945, 2945, 2945, 2946, 2946, 2946,
+     2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946,
+     2947, 2947, 2947, 2947, 2947, 2947, 2947, 2947, 2947, 2947,
+     2947, 2947, 2947, 2948, 2948,    0,    0, 2948, 2948, 2948,
+     2948, 2948, 2948, 2949, 2949,    0, 2949, 2949, 2949, 2949,
+     2949, 2949, 2949, 2949, 2949, 2949, 2950, 2950,    0, 2950,
+     2950, 2950, 2950, 2950, 2950, 2950, 2950, 2950, 2950, 2951,
+
+     2951,    0,    0, 2951, 2951, 2951, 2951, 2951, 2951, 2952,
+     2952,    0, 2952, 2952, 2952, 2952, 2952, 2952, 2952, 2952,
+     2952, 2952, 2953, 2953,    0, 2953, 2953, 2953, 2953, 2953,
+     2953, 2953, 2953, 2953, 2953, 2954, 2954,    0,    0, 2954,
+     2954, 2954, 2954, 2954, 2954, 2955, 2955,    0, 2955, 2955,
+     2955, 2955, 2955, 2955, 2955, 2955, 2955, 2955, 2956, 2956,
+        0, 2956, 2956, 2956, 2956, 2956, 2956, 2956, 2956, 2956,
+     2956, 2957, 2957,    0,    0, 2957, 2957, 2957, 2957, 2957,
+     2957, 2958, 2958,    0, 2958, 2958, 2958, 2958, 2958, 2958,
+     2958, 2958, 2958, 2958, 2959, 2959,    0, 2959, 2959, 2959,
+
+     2959, 2959, 2959, 2959, 2959, 2959, 2959, 2960, 2960,    0,
+        0, 2960, 2960, 2960, 2960, 2960, 2960, 2961, 2961,    0,
+     2961, 2961, 2961, 2961, 2961, 2961, 2961, 2961, 2961, 2961,
+     2962, 2962,    0, 2962, 2962, 2962, 2962, 2962, 2962, 2962,
+     2962, 2962, 2962, 2963, 2963,    0,    0, 2963, 2963, 2963,
+     2963, 2963, 2963, 2964, 2964,    0, 2964, 2964, 2964, 2964,
+     2964, 2964, 2964, 2964, 2964, 2964, 2965, 2965,    0, 2965,
+     2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2966,
+     2966,    0,    0, 2966, 2966, 2966, 2966, 2966, 2966, 2967,
+     2967,    0, 2967, 2967, 2967, 2967, 2967, 2967, 2967, 2967,
+
+     2967, 2967, 2968, 2968,    0, 2968, 2968, 2968, 2968, 2968,
+     2968, 2968, 2968, 2968, 2968, 2969, 2969,    0,    0, 2969,
+     2969, 2969, 2969, 2969, 2969, 2970, 2970,    0, 2970, 2970,
+     2970, 2970, 2970, 2970, 2970, 2970, 2970, 2970, 2971, 2971,
+        0, 2971, 2971, 2971, 2971, 2971, 2971, 2971, 2971, 2971,
+     2971, 2972, 2972,    0,    0, 2972, 2972, 2972, 2972, 2972,
+     2972, 2973, 2973,    0, 2973, 2973, 2973, 2973, 2973, 2973,
+     2973, 2973, 2973, 2973, 2974, 2974,    0, 2974, 2974, 2974,
+     2974, 2974, 2974, 2974, 2974, 2974, 2974, 2975, 2975,    0,
+        0, 2975, 2975, 2975, 2975, 2975, 2975, 2976, 2976,    0,
+
+     2976, 2976, 2976, 2976, 2976, 2976, 2976, 2976, 2976, 2976,
+     2977, 2977,    0, 2977, 2977, 2977, 2977, 2977, 2977, 2977,
+     2977, 2977, 2977, 2978, 2978,    0,    0, 2978, 2978, 2978,
+     2978, 2978, 2978, 2979, 2979,    0, 2979, 2979, 2979, 2979,
+     2979, 2979, 2979, 2979, 2979, 2979, 2980, 2980,    0, 2980,
+     2980, 2980, 2980, 2980, 2980, 2980, 2980, 2980, 2980, 2981,
+     2981, 2981, 2981,    0, 2981, 2981, 2981, 2981, 2981, 2981,
+     2981, 2981, 2982, 2982,    0, 2982,    0, 2982, 2982, 2982,
+     2982, 2982, 2982, 2982, 2982, 2983, 2983,    0,    0, 2983,
+     2983, 2983, 2983, 2983, 2983, 2984, 2984,    0, 2984, 2984,
+
+     2984, 2984, 2984, 2984, 2984, 2984, 2984, 2984, 2985, 2985,
+        0, 2985, 2985, 2985, 2985, 2985, 2985, 2985, 2985, 2985,
+     2985, 2986, 2986,    0,    0, 2986, 2986, 2986, 2986, 2986,
+     2986, 2987, 2987,    0, 2987, 2987, 2987, 2987, 2987, 2987,
+     2987, 2987, 2987, 2987, 2988, 2988,    0, 2988, 2988, 2988,
+     2988, 2988, 2988, 2988, 2988, 2988, 2988, 2989, 2989,    0,
+        0, 2989, 2989, 2989, 2989, 2989, 2989, 2990, 2990,    0,
+     2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990,
+     2991, 2991,    0, 2991, 2991, 2991, 2991, 2991, 2991, 2991,
+     2991, 2991, 2991, 2992, 2992,    0,    0, 2992, 2992, 2992,
+
+     2992, 2992, 2992, 2993, 2993,    0, 2993, 2993, 2993, 2993,
+     2993, 2993, 2993, 2993, 2993, 2993, 2994, 2994,    0, 2994,
+     2994, 2994, 2994, 2994, 2994, 2994, 2994, 2994, 2994, 2995,
+     2995, 2995, 2995, 2995, 2995,    0, 2995, 2995, 2995, 2995,
+     2995, 2995, 2996, 2996,    0,    0, 2996, 2996, 2996, 2996,
+     2996, 2996, 2997, 2997,    0, 2997, 2997, 2997, 2997, 2997,
+     2997, 2997, 2997, 2997, 2997, 2998, 2998,    0, 2998, 2998,
+     2998, 2998, 2998, 2998, 2998, 2998, 2998, 2998, 2999, 2999,
+        0,    0, 2999, 2999, 2999, 2999, 2999, 2999, 3000, 3000,
+        0, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000,
+
+     3000, 3001, 3001,    0, 3001, 3001, 3001, 3001, 3001, 3001,
+     3001, 3001, 3001, 3001, 3002, 3002,    0,    0, 3002, 3002,
+     3002, 3002, 3002, 3002, 3003, 3003,    0, 3003, 3003, 3003,
+     3003, 3003, 3003, 3003, 3003, 3003, 3003, 3004, 3004,    0,
+     3004, 3004, 3004, 3004, 3004, 3004, 3004, 3004, 3004, 3004,
+     3005, 3005,    0,    0, 3005, 3005, 3005, 3005, 3005, 3005,
+     3006, 3006,    0, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
+     3006, 3006, 3006, 3007, 3007,    0, 3007, 3007, 3007, 3007,
+     3007, 3007, 3007, 3007, 3007, 3007, 3008, 3008, 3008, 3008,
+     3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3008, 3009,
+
+     3009, 3009, 3009, 3009, 3009,    0, 3009, 3009, 3009, 3009,
+     3009, 3009, 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
+     3010, 3010, 3012, 3012, 3012, 3012, 3012, 3012, 3012, 3012,
+     3012,    0, 3012, 3012, 3012, 3013, 3013,    0, 3013, 3013,
+     3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3014, 3014,
+        0, 3014, 3014, 3014, 3014, 3014, 3014, 3014, 3014, 3014,
+     3014, 3015, 3015, 3015, 3015, 3015, 3015, 3015, 3015, 3015,
+     3015, 3015,    0, 3015, 3016, 3016,    0, 3016, 3016, 3016,
+     3016, 3016, 3016, 3016, 3016, 3016, 3016, 3017, 3017,    0,
+     3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
+
+     3018, 3018,    0,    0, 3018, 3018, 3018, 3018, 3018, 3018,
+     3019, 3019,    0, 3019, 3019, 3019, 3019, 3019, 3019, 3019,
+     3019, 3019, 3019, 3020, 3020,    0, 3020, 3020, 3020, 3020,
+     3020, 3020, 3020, 3020, 3020, 3020, 3021, 3021,    0,    0,
+     3021, 3021, 3021, 3021, 3021, 3021, 3022, 3022,    0, 3022,
+     3022, 3022, 3022, 3022, 3022, 3022, 3022, 3022, 3022, 3023,
+     3023,    0, 3023, 3023, 3023, 3023, 3023, 3023, 3023, 3023,
+     3023, 3023, 3024, 3024,    0,    0, 3024, 3024, 3024, 3024,
+     3024, 3024, 3025, 3025,    0, 3025, 3025, 3025, 3025, 3025,
+     3025, 3025, 3025, 3025, 3025, 3026, 3026,    0, 3026, 3026,
+
+     3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3027, 3027,
+        0,    0, 3027, 3027, 3027, 3027, 3027, 3027, 3028, 3028,
+        0, 3028, 3028, 3028, 3028, 3028, 3028, 3028, 3028, 3028,
+     3028, 3029, 3029,    0, 3029, 3029, 3029, 3029, 3029, 3029,
+     3029, 3029, 3029, 3029, 3030,    0, 3030, 3030,    0, 3030,
+     3030, 3030, 3030, 3030, 3030, 3030, 3030, 3031,    0, 3031,
+     3031,    0, 3031, 3031, 3031,    0, 3031, 3031, 3031, 3031,
+     3032, 3032,    0,    0, 3032, 3032, 3032, 3032, 3032, 3032,
+     3033, 3033,    0, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+     3033, 3033, 3033, 3034, 3034,    0, 3034, 3034, 3034, 3034,
+
+     3034, 3034, 3034, 3034, 3034, 3034, 3035,    0, 3035, 3035,
+        0, 3035, 3035, 3035, 3035, 3035, 3035, 3035, 3035, 3036,
+     3036,    0,    0, 3036, 3036, 3036, 3036, 3036, 3036, 3037,
+     3037,    0, 3037, 3037, 3037, 3037, 3037, 3037, 3037, 3037,
+     3037, 3037, 3038, 3038,    0, 3038, 3038, 3038, 3038, 3038,
+     3038, 3038, 3038, 3038, 3038, 3039,    0, 3039, 3039,    0,
+     3039, 3039, 3039, 3039, 3039, 3039, 3039, 3039, 3040, 3040,
+        0,    0, 3040, 3040, 3040, 3040, 3040, 3040, 3041, 3041,
+        0, 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
+     3041, 3042, 3042,    0, 3042, 3042, 3042, 3042, 3042, 3042,
+
+     3042, 3042, 3042, 3042, 3043, 3043,    0,    0, 3043, 3043,
+     3043, 3043, 3043, 3043, 3044, 3044,    0, 3044, 3044, 3044,
+     3044, 3044, 3044, 3044, 3044, 3044, 3044, 3045, 3045,    0,
+     3045, 3045, 3045, 3045, 3045, 3045, 3045, 3045, 3045, 3045,
+     3046, 3046,    0,    0, 3046, 3046, 3046, 3046, 3046, 3046,
+     3047, 3047,    0, 3047, 3047, 3047, 3047, 3047, 3047, 3047,
+     3047, 3047, 3047, 3048, 3048,    0, 3048, 3048, 3048, 3048,
+     3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,    0, 3049,
+     3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3050,
+     3050,    0, 3050, 3050, 3050, 3050, 3050, 3050, 3050, 3050,
+
+     3050, 3050, 3051, 3051,    0, 3051, 3051, 3051, 3051, 3051,
+     3051, 3051, 3051, 3051, 3051, 3052, 3052,    0,    0, 3052,
+     3052, 3052, 3052, 3052, 3052, 3053, 3053,    0, 3053, 3053,
+     3053, 3053, 3053, 3053, 3053, 3053, 3053, 3053, 3054, 3054,
+        0, 3054, 3054, 3054, 3054, 3054, 3054, 3054, 3054, 3054,
+     3054, 3055, 3055,    0,    0, 3055, 3055, 3055, 3055, 3055,
+     3055, 3056, 3056,    0, 3056, 3056, 3056, 3056, 3056, 3056,
+     3056, 3056, 3056, 3056, 3057, 3057,    0, 3057, 3057, 3057,
+     3057, 3057, 3057, 3057, 3057, 3057, 3057, 3058, 3058,    0,
+        0, 3058, 3058, 3058, 3058, 3058, 3058, 3059, 3059,    0,
+
+     3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
+     3060, 3060,    0, 3060, 3060, 3060, 3060, 3060, 3060, 3060,
+     3060, 3060, 3060, 3061, 3061,    0, 3061, 3061, 3061, 3061,
+     3061, 3061, 3061, 3061, 3061, 3061, 3062, 3062,    0, 3062,
+     3062, 3062, 3062, 3062, 3062, 3062, 3062, 3062, 3062, 3063,
+     3063,    0, 3063, 3063, 3063, 3063, 3063, 3063, 3063, 3063,
+     3063, 3063, 3064, 3064,    0,    0, 3064, 3064, 3064, 3064,
+     3064, 3064, 3065, 3065,    0, 3065, 3065, 3065, 3065, 3065,
+     3065, 3065, 3065, 3065, 3065, 3066, 3066,    0, 3066, 3066,
+     3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3067, 3067,
+
+        0,    0, 3067, 3067, 3067, 3067, 3067, 3067, 3068, 3068,
+        0, 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
+     3068, 3069, 3069,    0, 3069, 3069, 3069, 3069, 3069, 3069,
+     3069, 3069, 3069, 3069, 3070, 3070,    0,    0, 3070, 3070,
+     3070, 3070, 3070, 3070, 3071, 3071,    0, 3071, 3071, 3071,
+     3071, 3071, 3071, 3071, 3071, 3071, 3071, 3072, 3072,    0,
+     3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072,
+     3073, 3073,    0,    0, 3073, 3073, 3073, 3073, 3073, 3073,
+     3074, 3074,    0, 3074, 3074, 3074, 3074, 3074, 3074, 3074,
+     3074, 3074, 3074, 3075, 3075,    0, 3075, 3075, 3075, 3075,
+
+     3075, 3075, 3075, 3075, 3075, 3075, 3076, 3076,    0, 3076,
+     3076, 3076, 3076, 3076, 3076, 3076, 3076, 3076, 3076, 3077,
+     3077, 3077, 3077, 3077,    0, 3077, 3077, 3077, 3077, 3078,
+     3078,    0, 3078, 3078, 3078, 3078, 3078, 3078, 3078, 3078,
+     3078, 3078, 3079, 3079,    0, 3079, 3079, 3079, 3079, 3079,
+     3079, 3079, 3079, 3079, 3079, 3080, 3080,    0, 3080, 3080,
+     3080, 3080, 3080, 3080, 3080, 3080, 3080, 3080, 3081, 3081,
+        0, 3081, 3081, 3081, 3081, 3081, 3081, 3081, 3081, 3081,
+     3081, 3082, 3082,    0, 3082, 3082, 3082, 3082, 3082, 3082,
+     3082, 3082, 3082, 3082, 3083, 3083,    0, 3083, 3083, 3083,
+
+     3083, 3083, 3083, 3083, 3083, 3083, 3083, 3084, 3084,    0,
+     3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
+     3085, 3085,    0, 3085, 3085, 3085, 3085, 3085, 3085, 3085,
+     3085, 3085, 3085, 3086,    0, 3086, 3086,    0, 3086, 3086,
+     3086, 3086, 3086, 3086, 3086, 3086, 3087, 3087,    0,    0,
+     3087, 3087, 3087, 3087, 3087, 3087, 3088, 3088,    0, 3088,
+     3088, 3088, 3088, 3088, 3088, 3088, 3088, 3088, 3088, 3089,
+     3089,    0, 3089, 3089, 3089, 3089, 3089, 3089, 3089, 3089,
+     3089, 3089, 3090, 3090,    0, 3090, 3090, 3090, 3090, 3090,
+     3090, 3090, 3090, 3090, 3090, 3091, 3091,    0,    0, 3091,
+
+     3091, 3091, 3091, 3091, 3091, 3092, 3092,    0, 3092, 3092,
+     3092, 3092, 3092, 3092, 3092, 3092, 3092, 3092, 3093, 3093,
+        0, 3093, 3093, 3093, 3093, 3093, 3093, 3093, 3093, 3093,
+     3093, 3094, 3094,    0, 3094, 3094, 3094, 3094, 3094, 3094,
+     3094, 3094, 3094, 3094, 3095, 3095, 3095, 3095, 3095, 3095,
+     3095, 3095,    0, 3095, 3095, 3095, 3095, 3096, 3096,    0,
+        0, 3096, 3096, 3096, 3096, 3096, 3096, 3097, 3097, 3097,
+     3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097,
+     3098, 3098, 3098, 3098, 3098, 3098, 3098, 3098, 3098, 3098,
+     3098, 3098, 3098, 3099, 3099,    0, 3099, 3099, 3099, 3099,
+
+     3099, 3099, 3099, 3099, 3099, 3099, 3100, 3100,    0, 3100,
+     3100, 3100, 3100, 3100, 3100, 3100, 3100, 3100, 3100, 3101,
+     3101, 3101, 3101, 3101, 3101, 3101, 3101, 3101, 3101, 3101,
+     3101, 3101, 3102, 3102,    0, 3102, 3102, 3102, 3102, 3102,
+     3102, 3102, 3102, 3102, 3102, 3103, 3103,    0,    0, 3103,
+     3103, 3103, 3103, 3103, 3103, 3104, 3104,    0, 3104, 3104,
+     3104, 3104, 3104, 3104, 3104, 3104, 3104, 3104, 3105, 3105,
+        0, 3105, 3105, 3105, 3105, 3105, 3105, 3105, 3105, 3105,
+     3105, 3106, 3106,    0, 3106, 3106, 3106, 3106, 3106, 3106,
+     3106, 3106, 3106, 3106, 3107, 3107,    0,    0, 3107, 3107,
+
+     3107, 3107, 3107, 3107, 3108, 3108,    0, 3108, 3108, 3108,
+     3108, 3108, 3108, 3108, 3108, 3108, 3108, 3109, 3109,    0,
+     3109, 3109, 3109, 3109, 3109, 3109, 3109, 3109, 3109, 3109,
+     3110, 3110,    0, 3110, 3110, 3110, 3110, 3110, 3110, 3110,
+     3110, 3110, 3110, 3111, 3111,    0,    0, 3111, 3111, 3111,
+     3111, 3111, 3111, 3112, 3112,    0, 3112, 3112, 3112, 3112,
+     3112, 3112, 3112, 3112, 3112, 3112, 3113, 3113,    0, 3113,
+     3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3114,
+     3114,    0, 3114, 3114, 3114, 3114, 3114, 3114, 3114, 3114,
+     3114, 3114, 3115, 3115,    0,    0, 3115, 3115, 3115, 3115,
+
+     3115, 3115, 3116, 3116,    0, 3116, 3116, 3116, 3116, 3116,
+     3116, 3116, 3116, 3116, 3116, 3117, 3117,    0, 3117, 3117,
+     3117, 3117, 3117, 3117, 3117, 3117, 3117, 3117, 3118, 3118,
+        0, 3118, 3118, 3118, 3118, 3118, 3118, 3118, 3118, 3118,
+     3118, 3119, 3119,    0,    0, 3119, 3119, 3119, 3119, 3119,
+     3119, 3120, 3120,    0, 3120, 3120, 3120, 3120, 3120, 3120,
+     3120, 3120, 3120, 3120, 3121, 3121,    0, 3121, 3121, 3121,
+     3121, 3121, 3121, 3121, 3121, 3121, 3121, 3122, 3122,    0,
+     3122, 3122, 3122, 3122, 3122, 3122, 3122, 3122, 3122, 3122,
+     3123, 3123,    0,    0, 3123, 3123, 3123, 3123, 3123, 3123,
+
+     3124, 3124,    0, 3124, 3124, 3124, 3124, 3124, 3124, 3124,
+     3124, 3124, 3124, 3125, 3125,    0, 3125, 3125, 3125, 3125,
+     3125, 3125, 3125, 3125, 3125, 3125, 3126, 3126,    0, 3126,
+     3126, 3126, 3126, 3126, 3126, 3126, 3126, 3126, 3126, 3127,
+     3127,    0,    0, 3127, 3127, 3127, 3127, 3127, 3127, 3128,
+     3128,    0, 3128, 3128, 3128, 3128, 3128, 3128, 3128, 3128,
+     3128, 3128, 3129, 3129,    0, 3129, 3129, 3129, 3129, 3129,
+     3129, 3129, 3129, 3129, 3129, 3130, 3130,    0, 3130, 3130,
+     3130, 3130, 3130, 3130, 3130, 3130, 3130, 3130, 3131, 3131,
+        0,    0, 3131, 3131, 3131, 3131, 3131, 3131, 3132, 3132,
+
+        0, 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
+     3132, 3133, 3133,    0, 3133, 3133, 3133, 3133, 3133, 3133,
+     3133, 3133, 3133, 3133, 3134, 3134,    0, 3134, 3134, 3134,
+     3134, 3134, 3134, 3134, 3134, 3134, 3134, 3135, 3135,    0,
+        0, 3135, 3135, 3135, 3135, 3135, 3135, 3136, 3136,    0,
+     3136, 3136, 3136, 3136, 3136, 3136, 3136, 3136, 3136, 3136,
+     3137, 3137,    0, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
+     3137, 3137, 3137, 3138, 3138,    0, 3138, 3138, 3138, 3138,
+     3138, 3138, 3138, 3138, 3138, 3138, 3139, 3139,    0,    0,
+     3139, 3139, 3139, 3139, 3139, 3139, 3140, 3140,    0, 3140,
+
+     3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3141,
+     3141,    0, 3141, 3141, 3141, 3141, 3141, 3141, 3141, 3141,
+     3141, 3141, 3142, 3142,    0, 3142, 3142, 3142, 3142, 3142,
+     3142, 3142, 3142, 3142, 3142, 3143, 3143,    0,    0, 3143,
+     3143, 3143, 3143, 3143, 3143, 3144, 3144,    0, 3144, 3144,
+     3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3145, 3145,
+        0, 3145, 3145, 3145, 3145, 3145, 3145, 3145, 3145, 3145,
+     3145, 3146, 3146,    0, 3146, 3146, 3146, 3146, 3146, 3146,
+     3146, 3146, 3146, 3146, 3147, 3147, 3147, 3147,    0, 3147,
+     3147, 3147, 3147, 3147, 3147, 3147, 3147, 3148, 3148,    0,
+
+     3148,    0, 3148, 3148, 3148, 3148, 3148, 3148, 3148, 3148,
+     3149, 3149,    0,    0, 3149, 3149, 3149, 3149, 3149, 3149,
+     3150, 3150,    0, 3150, 3150, 3150, 3150, 3150, 3150, 3150,
+     3150, 3150, 3150, 3151, 3151,    0, 3151, 3151, 3151, 3151,
+     3151, 3151, 3151, 3151, 3151, 3151, 3152, 3152,    0, 3152,
+     3152, 3152, 3152, 3152, 3152, 3152, 3152, 3152, 3152, 3153,
+     3153,    0,    0, 3153, 3153, 3153, 3153, 3153, 3153, 3154,
+     3154,    0, 3154, 3154, 3154, 3154, 3154, 3154, 3154, 3154,
+     3154, 3154, 3155, 3155,    0, 3155, 3155, 3155, 3155, 3155,
+     3155, 3155, 3155, 3155, 3155, 3156, 3156,    0, 3156, 3156,
+
+     3156, 3156, 3156, 3156, 3156, 3156, 3156, 3156, 3157, 3157,
+        0,    0, 3157, 3157, 3157, 3157, 3157, 3157, 3158, 3158,
+        0, 3158, 3158, 3158, 3158, 3158, 3158, 3158, 3158, 3158,
+     3158, 3159, 3159,    0, 3159, 3159, 3159, 3159, 3159, 3159,
+     3159, 3159, 3159, 3159, 3160, 3160,    0, 3160, 3160, 3160,
+     3160, 3160, 3160, 3160, 3160, 3160, 3160, 3161, 3161,    0,
+        0, 3161, 3161, 3161, 3161, 3161, 3161, 3162, 3162,    0,
+     3162, 3162, 3162, 3162, 3162, 3162, 3162, 3162, 3162, 3162,
+     3163, 3163,    0, 3163, 3163, 3163, 3163, 3163, 3163, 3163,
+     3163, 3163, 3163, 3164, 3164,    0, 3164, 3164, 3164, 3164,
+
+     3164, 3164, 3164, 3164, 3164, 3164, 3165, 3165, 3165, 3165,
+     3165, 3165,    0, 3165, 3165, 3165, 3165, 3165, 3165, 3166,
+     3166,    0,    0, 3166, 3166, 3166, 3166, 3166, 3166, 3167,
+     3167,    0, 3167, 3167, 3167, 3167, 3167, 3167, 3167, 3167,
+     3167, 3167, 3168, 3168,    0, 3168, 3168, 3168, 3168, 3168,
+     3168, 3168, 3168, 3168, 3168, 3169, 3169,    0, 3169, 3169,
+     3169, 3169, 3169, 3169, 3169, 3169, 3169, 3169, 3170, 3170,
+        0,    0, 3170, 3170, 3170, 3170, 3170, 3170, 3171, 3171,
+        0, 3171, 3171, 3171, 3171, 3171, 3171, 3171, 3171, 3171,
+     3171, 3172, 3172,    0, 3172, 3172, 3172, 3172, 3172, 3172,
+
+     3172, 3172, 3172, 3172, 3173, 3173,    0, 3173, 3173, 3173,
+     3173, 3173, 3173, 3173, 3173, 3173, 3173, 3174, 3174,    0,
+        0, 3174, 3174, 3174, 3174, 3174, 3174, 3175, 3175,    0,
+     3175, 3175, 3175, 3175, 3175, 3175, 3175, 3175, 3175, 3175,
+     3176, 3176,    0, 3176, 3176, 3176, 3176, 3176, 3176, 3176,
+     3176, 3176, 3176, 3177, 3177,    0, 3177, 3177, 3177, 3177,
+     3177, 3177, 3177, 3177, 3177, 3177, 3178, 3178,    0,    0,
+     3178, 3178, 3178, 3178, 3178, 3178, 3179, 3179,    0, 3179,
+     3179, 3179, 3179, 3179, 3179, 3179, 3179, 3179, 3179, 3180,
+     3180,    0, 3180, 3180, 3180, 3180, 3180, 3180, 3180, 3180,
+
+     3180, 3180, 3181, 3181,    0, 3181, 3181, 3181, 3181, 3181,
+     3181, 3181, 3181, 3181, 3181, 3182, 3182, 3182, 3182, 3182,
+     3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3183, 3183,
+     3183, 3183, 3183, 3183, 3183, 3183, 3183, 3183, 3183, 3183,
+     3183, 3184, 3184, 3184, 3184, 3184, 3184, 3184, 3184, 3184,
+     3184, 3184, 3184, 3184, 3185, 3185, 3185, 3185, 3185, 3185,
+     3185, 3185, 3185, 3185, 3185, 3185, 3185, 3186, 3186, 3186,
+     3186, 3186, 3186, 3186, 3186, 3186, 3186, 3186, 3186, 3186,
+     3187, 3187,    0, 3187, 3187, 3187, 3187, 3187, 3187, 3187,
+     3187, 3187, 3187, 3188, 3188,    0, 3188, 3188, 3188, 3188,
+
+     3188, 3188, 3188, 3188, 3188, 3188, 3189, 3189,    0, 3189,
+     3189, 3189, 3189, 3189, 3189, 3189, 3189, 3189, 3189, 3191,
+     3191,    0, 3191, 3191, 3191, 3191, 3191, 3191, 3191, 3191,
+     3191, 3191, 3192, 3192,    0, 3192, 3192, 3192, 3192, 3192,
+     3192, 3192, 3192, 3192, 3192, 3193, 3193, 3193, 3193, 3193,
+     3193, 3193, 3193, 3193, 3193, 3193,    0, 3193, 3194, 3194,
+        0, 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
+     3194, 3195, 3195,    0, 3195, 3195, 3195, 3195, 3195, 3195,
+     3195, 3195, 3195, 3195, 3196, 3196, 3196, 3196, 3196, 3196,
+     3196, 3196, 3196, 3196, 3196, 3196, 3196, 3197, 3197, 3197,
+
+     3197, 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3197,
+     3198, 3198, 3198, 3198, 3198, 3198, 3198, 3198, 3198, 3198,
+     3198, 3198, 3198, 3199, 3199, 3199, 3199, 3199, 3199, 3199,
+     3199, 3199, 3199, 3199, 3199, 3199, 3200, 3200, 3200, 3200,
+     3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3201,
+     3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+     3201, 3201, 3202, 3202,    0, 3202, 3202, 3202, 3202, 3202,
+     3202, 3202, 3202, 3202, 3202, 3203, 3203,    0,    0, 3203,
+     3203, 3203, 3203, 3203, 3203, 3204, 3204,    0, 3204, 3204,
+     3204, 3204, 3204, 3204, 3204, 3204, 3204, 3204, 3205, 3205,
+
+        0, 3205, 3205, 3205, 3205, 3205, 3205, 3205, 3205, 3205,
+     3205, 3206, 3206,    0, 3206, 3206, 3206, 3206, 3206, 3206,
+     3206, 3206, 3206, 3206, 3207, 3207,    0,    0, 3207, 3207,
+     3207, 3207, 3207, 3207, 3208, 3208,    0, 3208, 3208, 3208,
+     3208, 3208, 3208, 3208, 3208, 3208, 3208, 3209, 3209,    0,
+     3209, 3209, 3209, 3209, 3209, 3209, 3209, 3209, 3209, 3209,
+     3210, 3210,    0, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+     3210, 3210, 3210, 3211, 3211,    0,    0, 3211, 3211, 3211,
+     3211, 3211, 3211, 3212, 3212,    0, 3212, 3212, 3212, 3212,
+     3212, 3212, 3212, 3212, 3212, 3212, 3213, 3213,    0, 3213,
+
+     3213, 3213, 3213, 3213, 3213, 3213, 3213, 3213, 3213, 3214,
+     3214,    0, 3214, 3214, 3214, 3214, 3214, 3214, 3214, 3214,
+     3214, 3214, 3215, 3215,    0,    0, 3215, 3215, 3215, 3215,
+     3215, 3215, 3216, 3216,    0, 3216, 3216, 3216, 3216, 3216,
+     3216, 3216, 3216, 3216, 3216, 3217, 3217,    0, 3217, 3217,
+     3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3218, 3218,
+        0, 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
+     3218, 3219,    0, 3219, 3219,    0, 3219, 3219, 3219, 3219,
+     3219, 3219, 3219, 3219, 3220,    0, 3220, 3220,    0, 3220,
+     3220, 3220,    0, 3220, 3220, 3220, 3220, 3221, 3221,    0,
+
+        0, 3221, 3221, 3221, 3221, 3221, 3221, 3222, 3222,    0,
+     3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
+     3223, 3223,    0, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
+     3223, 3223, 3223, 3224, 3224,    0, 3224, 3224, 3224, 3224,
+     3224, 3224, 3224, 3224, 3224, 3224, 3225,    0, 3225, 3225,
+        0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3226,
+     3226,    0,    0, 3226, 3226, 3226, 3226, 3226, 3226, 3227,
+     3227,    0, 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+     3227, 3227, 3228, 3228,    0, 3228, 3228, 3228, 3228, 3228,
+     3228, 3228, 3228, 3228, 3228, 3229, 3229,    0, 3229, 3229,
+
+     3229, 3229, 3229, 3229, 3229, 3229, 3229, 3229, 3230,    0,
+     3230, 3230,    0, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+     3230, 3231, 3231,    0,    0, 3231, 3231, 3231, 3231, 3231,
+     3231, 3232, 3232,    0, 3232, 3232, 3232, 3232, 3232, 3232,
+     3232, 3232, 3232, 3232, 3233, 3233,    0, 3233, 3233, 3233,
+     3233, 3233, 3233, 3233, 3233, 3233, 3233, 3234, 3234,    0,
+     3234, 3234, 3234, 3234, 3234, 3234, 3234, 3234, 3234, 3234,
+     3235, 3235,    0,    0, 3235, 3235, 3235, 3235, 3235, 3235,
+     3236, 3236,    0, 3236, 3236, 3236, 3236, 3236, 3236, 3236,
+     3236, 3236, 3236, 3237, 3237,    0, 3237, 3237, 3237, 3237,
+
+     3237, 3237, 3237, 3237, 3237, 3237, 3238, 3238,    0, 3238,
+     3238, 3238, 3238, 3238, 3238, 3238, 3238, 3238, 3238, 3239,
+     3239,    0,    0, 3239, 3239, 3239, 3239, 3239, 3239, 3240,
+     3240,    0, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240,
+     3240, 3240, 3241, 3241,    0, 3241, 3241, 3241, 3241, 3241,
+     3241, 3241, 3241, 3241, 3241, 3242, 3242,    0, 3242, 3242,
+     3242, 3242, 3242, 3242, 3242, 3242, 3242, 3242, 3243, 3243,
+        0, 3243, 3243, 3243, 3243, 3243, 3243, 3243, 3243, 3243,
+     3243, 3244, 3244,    0, 3244, 3244, 3244, 3244, 3244, 3244,
+     3244, 3244, 3244, 3244, 3245, 3245,    0,    0, 3245, 3245,
+
+     3245, 3245, 3245, 3245, 3246, 3246,    0, 3246, 3246, 3246,
+     3246, 3246, 3246, 3246, 3246, 3246, 3246, 3247, 3247,    0,
+     3247, 3247, 3247, 3247, 3247, 3247, 3247, 3247, 3247, 3247,
+     3248, 3248,    0, 3248, 3248, 3248, 3248, 3248, 3248, 3248,
+     3248, 3248, 3248, 3249, 3249,    0,    0, 3249, 3249, 3249,
+     3249, 3249, 3249, 3250, 3250,    0, 3250, 3250, 3250, 3250,
+     3250, 3250, 3250, 3250, 3250, 3250, 3251, 3251,    0, 3251,
+     3251, 3251, 3251, 3251, 3251, 3251, 3251, 3251, 3251, 3252,
+     3252,    0, 3252, 3252, 3252, 3252, 3252, 3252, 3252, 3252,
+     3252, 3252, 3253, 3253,    0,    0, 3253, 3253, 3253, 3253,
+
+     3253, 3253, 3254, 3254,    0, 3254, 3254, 3254, 3254, 3254,
+     3254, 3254, 3254, 3254, 3254, 3255, 3255,    0, 3255, 3255,
+     3255, 3255, 3255, 3255, 3255, 3255, 3255, 3255, 3256, 3256,
+        0, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256, 3256,
+     3256, 3257, 3257,    0, 3257, 3257, 3257, 3257, 3257, 3257,
+     3257, 3257, 3257, 3257, 3258, 3258,    0, 3258, 3258, 3258,
+     3258, 3258, 3258, 3258, 3258, 3258, 3258, 3259, 3259,    0,
+        0, 3259, 3259, 3259, 3259, 3259, 3259, 3260, 3260,    0,
+     3260, 3260, 3260, 3260, 3260, 3260, 3260, 3260, 3260, 3260,
+     3261, 3261,    0, 3261, 3261, 3261, 3261, 3261, 3261, 3261,
+
+     3261, 3261, 3261, 3262, 3262,    0, 3262, 3262, 3262, 3262,
+     3262, 3262, 3262, 3262, 3262, 3262, 3263, 3263,    0,    0,
+     3263, 3263, 3263, 3263, 3263, 3263, 3264, 3264,    0, 3264,
+     3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3264, 3265,
+     3265,    0, 3265, 3265, 3265, 3265, 3265, 3265, 3265, 3265,
+     3265, 3265, 3266, 3266,    0, 3266, 3266, 3266, 3266, 3266,
+     3266, 3266, 3266, 3266, 3266, 3267, 3267,    0,    0, 3267,
+     3267, 3267, 3267, 3267, 3267, 3268, 3268,    0, 3268, 3268,
+     3268, 3268, 3268, 3268, 3268, 3268, 3268, 3268, 3269, 3269,
+        0, 3269, 3269, 3269, 3269, 3269, 3269, 3269, 3269, 3269,
+
+     3269, 3270, 3270,    0, 3270, 3270, 3270, 3270, 3270, 3270,
+     3270, 3270, 3270, 3270, 3271, 3271,    0,    0, 3271, 3271,
+     3271, 3271, 3271, 3271, 3272, 3272,    0, 3272, 3272, 3272,
+     3272, 3272, 3272, 3272, 3272, 3272, 3272, 3273, 3273,    0,
+     3273, 3273, 3273, 3273, 3273, 3273, 3273, 3273, 3273, 3273,
+     3274, 3274,    0, 3274, 3274, 3274, 3274, 3274, 3274, 3274,
+     3274, 3274, 3274, 3275, 3275, 3275, 3275, 3275,    0, 3275,
+     3275, 3275, 3275, 3276, 3276, 3276, 3276, 3276, 3276, 3276,
+     3276, 3276, 3276, 3276, 3276, 3276, 3277, 3277,    0, 3277,
+     3277, 3277, 3277, 3277, 3277, 3277, 3277, 3277, 3277, 3278,
+
+     3278,    0, 3278, 3278, 3278, 3278, 3278, 3278, 3278, 3278,
+     3278, 3278, 3279, 3279,    0, 3279, 3279, 3279, 3279, 3279,
+     3279, 3279, 3279, 3279, 3279, 3280, 3280,    0, 3280, 3280,
+     3280, 3280, 3280, 3280, 3280, 3280, 3280, 3280, 3281, 3281,
+        0, 3281, 3281, 3281, 3281, 3281, 3281, 3281, 3281, 3281,
+     3281, 3282,    0, 3282, 3282,    0, 3282, 3282, 3282, 3282,
+     3282, 3282, 3282, 3282, 3283, 3283,    0, 3283, 3283, 3283,
+     3283, 3283, 3283, 3283, 3283, 3283, 3283, 3284, 3284,    0,
+     3284, 3284, 3284, 3284, 3284, 3284, 3284, 3284, 3284, 3284,
+     3285, 3285, 3285, 3285, 3285, 3285, 3285, 3285, 3285, 3285,
+
+     3285, 3285, 3285, 3286, 3286,    0, 3286, 3286, 3286, 3286,
+     3286, 3286, 3286, 3286, 3286, 3286, 3287, 3287,    0, 3287,
+     3287, 3287, 3287, 3287, 3287, 3287, 3287, 3287, 3287, 3288,
+     3288,    0, 3288, 3288, 3288, 3288, 3288, 3288, 3288, 3288,
+     3288, 3288, 3289, 3289,    0, 3289, 3289, 3289, 3289, 3289,
+     3289, 3289, 3289, 3289, 3289, 3290, 3290,    0, 3290, 3290,
+     3290, 3290, 3290, 3290, 3290, 3290, 3290, 3290, 3291, 3291,
+        0, 3291, 3291, 3291, 3291, 3291, 3291, 3291, 3291, 3291,
+     3291, 3292, 3292,    0, 3292, 3292, 3292, 3292, 3292, 3292,
+     3292, 3292, 3292, 3292, 3293, 3293,    0, 3293, 3293, 3293,
+
+     3293, 3293, 3293, 3293, 3293, 3293, 3293, 3294, 3294,    0,
+     3294, 3294, 3294, 3294, 3294, 3294, 3294, 3294, 3294, 3294,
+     3295, 3295,    0, 3295, 3295, 3295, 3295, 3295, 3295, 3295,
+     3295, 3295, 3295, 3296, 3296,    0, 3296, 3296, 3296, 3296,
+     3296, 3296, 3296, 3296, 3296, 3296, 3297, 3297,    0, 3297,
+     3297, 3297, 3297, 3297, 3297, 3297, 3297, 3297, 3297, 3298,
+     3298,    0, 3298, 3298, 3298, 3298, 3298, 3298, 3298, 3298,
+     3298, 3298, 3299, 3299,    0, 3299, 3299, 3299, 3299, 3299,
+     3299, 3299, 3299, 3299, 3299, 3300, 3300,    0, 3300, 3300,
+     3300, 3300, 3300, 3300, 3300, 3300, 3300, 3300, 3301, 3301,
+
+        0, 3301, 3301, 3301, 3301, 3301, 3301, 3301, 3301, 3301,
+     3301, 3302, 3302,    0, 3302, 3302, 3302, 3302, 3302, 3302,
+     3302, 3302, 3302, 3302, 3303, 3303,    0, 3303, 3303, 3303,
+     3303, 3303, 3303, 3303, 3303, 3303, 3303, 3304, 3304,    0,
+     3304, 3304, 3304, 3304, 3304, 3304, 3304, 3304, 3304, 3304,
+     3305, 3305,    0, 3305, 3305, 3305, 3305, 3305, 3305, 3305,
+     3305, 3305, 3305, 3306, 3306, 3306, 3306, 3306, 3306, 3306,
+     3306, 3306, 3306, 3306, 3306, 3306, 3307, 3307, 3307, 3307,
+     3307, 3307, 3307, 3307, 3307, 3307, 3307, 3307, 3307, 3308,
+     3308, 3308, 3308, 3308, 3308, 3308, 3308, 3308, 3308, 3308,
+
+     3308, 3308, 3309, 3309, 3309, 3309, 3309, 3309, 3309, 3309,
+     3309, 3309, 3309, 3309, 3309, 3310, 3310, 3310, 3310, 3310,
+     3310, 3310, 3310, 3310, 3310, 3310, 3310, 3310, 3311, 3311,
+     3311, 3311, 3311, 3311, 3311, 3311, 3311, 3311, 3311, 3311,
+     3311, 3312, 3312, 3312, 3312, 3312, 3312, 3312, 3312, 3312,
+     3312, 3312, 3312, 3312, 3313, 3313, 3313, 3313, 3313, 3313,
+     3313, 3313, 3313, 3313, 3313, 3313, 3313, 3314, 3314,    0,
+     3314, 3314, 3314, 3314, 3314, 3314, 3314, 3314, 3314, 3314,
+     3315, 3315, 3315, 3315, 3315, 3315, 3315, 3315, 3315, 3315,
+     3315, 3315, 3315, 3316, 3316, 3316, 3316, 3316, 3316, 3316,
+
+     3316, 3316, 3316, 3316, 3316, 3316, 3317, 3317, 3317, 3317,
+     3317, 3317, 3317, 3317, 3317, 3317, 3317, 3317, 3317, 3318,
+     3318,    0, 3318, 3318, 3318, 3318, 3318, 3318, 3318, 3318,
+     3318, 3318, 3319, 3319,    0, 3319, 3319, 3319, 3319, 3319,
+     3319, 3319, 3319, 3319, 3319, 3320, 3320, 3320, 3320, 3320,
+     3320, 3320, 3320, 3320, 3320, 3320, 3320, 3320, 3321, 3321,
+     3321, 3321, 3321, 3321, 3321, 3321, 3321, 3321, 3321, 3321,
+     3321, 3322, 3322, 3322, 3322, 3322, 3322, 3322, 3322, 3322,
+     3322, 3322, 3322, 3322, 3323, 3323, 3323, 3323, 3323, 3323,
+     3323, 3323, 3323, 3323, 3323, 3323, 3323, 3324, 3324, 3324,
+
+     3324, 3324, 3324, 3324, 3324, 3324, 3324, 3324, 3324, 3324,
+     3325, 3325, 3325, 3325, 3325, 3325, 3325, 3325, 3325, 3325,
+     3325, 3325, 3325, 3326, 3326, 3326, 3326, 3326, 3326, 3326,
+     3326, 3326, 3326, 3326, 3326, 3326, 3327, 3327, 3327, 3327,
+     3327, 3327, 3327, 3327, 3327, 3327, 3327, 3327, 3327, 3328,
+     3328,    0, 3328, 3328, 3328, 3328, 3328, 3328, 3328, 3328,
+     3328, 3328, 3329, 3329, 3329, 3329, 3329, 3329, 3329, 3329,
+     3329, 3329, 3329, 3329, 3329, 3330, 3330, 3330, 3330, 3330,
+     3330, 3330, 3330, 3330, 3330, 3330, 3330, 3330, 3331, 3331,
+     3331, 3331, 3331, 3331, 3331, 3331, 3331, 3331, 3331, 3331,
+
+     3331, 3333, 3333,    0, 3333, 3333, 3333, 3333, 3333, 3333,
+     3333, 3333, 3333, 3333, 3334, 3334,    0, 3334, 3334, 3334,
+     3334, 3334, 3334, 3334, 3334, 3334, 3334, 3335, 3335,    0,
+     3335, 3335, 3335, 3335, 3335, 3335, 3335, 3335, 3335, 3335,
+     3336, 3336,    0, 3336, 3336, 3336, 3336, 3336, 3336, 3336,
+     3336, 3336, 3336, 3337, 3337,    0, 3337, 3337, 3337, 3337,
+     3337, 3337, 3337, 3337, 3337, 3337, 3338, 3338,    0, 3338,
+     3338, 3338, 3338, 3338, 3338, 3338, 3338, 3338, 3338, 3339,
+     3339,    0, 3339, 3339, 3339, 3339, 3339, 3339, 3339, 3339,
+     3339, 3339, 3340, 3340,    0, 3340, 3340, 3340, 3340, 3340,
+
+     3340, 3340, 3340, 3340, 3340, 3341, 3341,    0, 3341, 3341,
+     3341, 3341, 3341, 3341, 3341, 3341, 3341, 3341, 3342, 3342,
+        0, 3342, 3342, 3342, 3342, 3342, 3342, 3342, 3342, 3342,
+     3342, 3343, 3343,    0, 3343, 3343, 3343, 3343, 3343, 3343,
+     3343, 3343, 3343, 3343, 3344, 3344,    0, 3344, 3344, 3344,
+     3344, 3344, 3344, 3344, 3344, 3344, 3344, 3345, 3345,    0,
+     3345, 3345, 3345, 3345, 3345, 3345, 3345, 3345, 3345, 3345,
+     3346, 3346,    0, 3346, 3346, 3346, 3346, 3346, 3346, 3346,
+     3346, 3346, 3346, 3347, 3347,    0, 3347, 3347, 3347, 3347,
+     3347, 3347, 3347, 3347, 3347, 3347, 3348, 3348,    0, 3348,
+
+     3348, 3348, 3348, 3348, 3348, 3348, 3348, 3348, 3348, 3349,
+     3349,    0, 3349, 3349, 3349, 3349, 3349, 3349, 3349, 3349,
+     3349, 3349, 3350, 3350,    0, 3350, 3350, 3350, 3350, 3350,
+     3350, 3350, 3350, 3350, 3350, 3351, 3351,    0, 3351, 3351,
+     3351, 3351, 3351, 3351, 3351, 3351, 3351, 3351, 3352, 3352,
+     3352, 3352, 3352,    0, 3352, 3352, 3352, 3352, 3353, 3353,
+     3353, 3353, 3353, 3353, 3353, 3353, 3353, 3353, 3353, 3353,
+     3353, 3354, 3354, 3354, 3354, 3354, 3354, 3354, 3354, 3354,
+     3354, 3354, 3354, 3354, 3355, 3355, 3355, 3355, 3355, 3355,
+     3355, 3355, 3355, 3355, 3355, 3355, 3355, 3356, 3356, 3356,
+
+     3356, 3356, 3356, 3356, 3356, 3356, 3356, 3356, 3356, 3356,
+     3357, 3357,    0, 3357, 3357, 3357, 3357, 3357, 3357, 3357,
+     3357, 3357, 3357, 3358, 3358,    0, 3358, 3358, 3358, 3358,
+     3358, 3358, 3358, 3358, 3358, 3358, 3359, 3359, 3359, 3359,
+     3359, 3359, 3359, 3359, 3359, 3359, 3359, 3359, 3359, 3360,
+     3360, 3360, 3360, 3360, 3360, 3360, 3360, 3360, 3360, 3360,
+     3360, 3360, 3361, 3361, 3361, 3361, 3361, 3361, 3361, 3361,
+     3361, 3361, 3361, 3361, 3361, 3362, 3362,    0, 3362, 3362,
+     3362, 3362, 3362, 3362, 3362, 3362, 3362, 3362, 3363, 3363,
+     3363, 3363, 3363, 3363, 3363, 3363, 3363, 3363, 3363, 3363,
+
+     3363, 3364, 3364, 3364, 3364, 3364, 3364, 3364, 3364, 3364,
+     3364, 3364, 3364, 3364, 3365, 3365, 3365, 3365, 3365, 3365,
+     3365, 3365, 3365, 3365, 3365, 3365, 3365, 3366, 3366, 3366,
+     3366, 3366, 3366, 3366, 3366, 3366, 3366, 3366, 3366, 3366,
+     3367, 3367, 3367, 3367, 3367, 3367, 3367, 3367, 3367, 3367,
+     3367, 3367, 3367, 3368, 3368, 3368, 3368, 3368, 3368, 3368,
+     3368, 3368, 3368, 3368, 3368, 3368, 3369, 3369, 3369, 3369,
+     3369, 3369, 3369, 3369, 3369, 3369, 3369, 3369, 3369, 3370,
+     3370, 3370, 3370, 3370, 3370, 3370, 3370, 3370, 3370, 3370,
+     3370, 3370, 3371, 3371, 3371, 3371, 3371, 3371, 3371, 3371,
+
+     3371, 3371, 3371, 3371, 3371, 3372, 3372, 3372, 3372, 3372,
+     3372, 3372, 3372, 3372, 3372, 3372, 3372, 3372, 3373, 3373,
+     3373, 3373, 3373, 3373, 3373, 3373, 3373, 3373, 3373, 3373,
+     3373, 3374, 3374, 3374, 3374, 3374, 3374, 3374, 3374, 3374,
+     3374, 3374, 3374, 3374, 3375, 3375, 3375, 3375, 3375, 3375,
+     3375, 3375, 3375, 3375, 3375, 3375, 3375, 3376, 3376, 3376,
+     3376, 3376, 3376, 3376, 3376, 3376, 3376, 3376, 3376, 3376,
+     3377, 3377, 3377, 3377, 3377, 3377, 3377, 3377, 3377, 3377,
+     3377, 3377, 3377, 3378, 3378, 3378, 3378, 3378, 3378, 3378,
+     3378, 3378, 3378, 3378, 3378, 3378, 3379, 3379, 3379, 3379,
+
+     3379, 3379, 3379, 3379, 3379, 3379, 3379, 3379, 3379, 3380,
+     3380,    0, 3380, 3380, 3380, 3380, 3380, 3380, 3380, 3380,
+     3380, 3380, 3381, 3381, 3381, 3381, 3381, 3381, 3381, 3381,
+     3381, 3381, 3381, 3381, 3381, 3382, 3382, 3382, 3382, 3382,
+     3382, 3382, 3382, 3382, 3382, 3382, 3382, 3382, 3383, 3383,
+     3383, 3383, 3383, 3383, 3383, 3383, 3383, 3383, 3383, 3383,
+     3383, 3384, 3384, 3384, 3384, 3384, 3384, 3384, 3384, 3384,
+     3384, 3384, 3384, 3384, 3385, 3385, 3385, 3385, 3385, 3385,
+     3385, 3385, 3385, 3385, 3385, 3385, 3385, 3386, 3386, 3386,
+     3386, 3386, 3386, 3386, 3386, 3386, 3386, 3386, 3386, 3386,
+
+     3387, 3387, 3387, 3387, 3387, 3387, 3387, 3387, 3387, 3387,
+     3387, 3387, 3387, 3388, 3388, 3388, 3388, 3388, 3388, 3388,
+     3388, 3388, 3388, 3388, 3388, 3388, 3389, 3389, 3389, 3389,
+     3389, 3389, 3389, 3389, 3389, 3389, 3389, 3389, 3389, 3390,
+     3390, 3390, 3390, 3390, 3390, 3390, 3390, 3390, 3390, 3390,
+     3390, 3390, 3391, 3391, 3391, 3391, 3391, 3391, 3391, 3391,
+     3391, 3391, 3391, 3391, 3391, 3392, 3392, 3392, 3392, 3392,
+     3392, 3392, 3392, 3392, 3392, 3392, 3392, 3392, 3393, 3393,
+     3393, 3393, 3393, 3393, 3393, 3393, 3393, 3393, 3393, 3393,
+     3393, 3394, 3394, 3394, 3394, 3394, 3394, 3394, 3394, 3394,
+
+     3394, 3394, 3394, 3394, 3395, 3395, 3395, 3395, 3395, 3395,
+     3395, 3395, 3395, 3395, 3395, 3395, 3395, 3396, 3396, 3396,
+     3396, 3396, 3396, 3396, 3396, 3396, 3396, 3396, 3396, 3396,
+     3397, 3397, 3397, 3397, 3397, 3397, 3397, 3397, 3397, 3397,
+     3397, 3397, 3397, 3398, 3398, 3398, 3398, 3398,    0, 3398,
+     3398, 3398, 3398, 3399, 3399,    0, 3399, 3399, 3399, 3399,
+     3399, 3399, 3399, 3399, 3399, 3399, 3400, 3400,    0, 3400,
+     3400, 3400, 3400, 3400, 3400, 3400, 3400, 3400, 3400, 3401,
+     3401, 3401, 3401, 3401, 3401, 3401, 3401, 3401, 3401, 3401,
+     3401, 3401, 3402, 3402, 3402, 3402, 3402, 3402, 3402, 3402,
+
+     3402, 3402, 3402, 3402, 3402, 3403, 3403, 3403, 3403, 3403,
+     3403, 3403, 3403, 3403, 3403, 3403, 3403, 3403, 3404, 3404,
+     3404, 3404, 3404, 3404, 3404, 3404,    0, 3404, 3404, 3404,
+     3404, 3405, 3405, 3405, 3405, 3405, 3405, 3405, 3405, 3405,
+     3405, 3405, 3405, 3405, 3406, 3406, 3406, 3406, 3406, 3406,
+     3406, 3406, 3406, 3406, 3406, 3406, 3406, 3407, 3407, 3407,
+     3407, 3407, 3407, 3407, 3407,    0, 3407, 3407, 3407, 3407,
+     3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408, 3408,
+     3408, 3408, 3408, 3409, 3409, 3409, 3409, 3409, 3409, 3409,
+     3409, 3409, 3409, 3409, 3409, 3409, 3410, 3410, 3410, 3410,
+
+     3410, 3410, 3410, 3410, 3410, 3410, 3410, 3410, 3410, 3411,
+     3411, 3411, 3411, 3411, 3411, 3411, 3411, 3411, 3411, 3411,
+     3411, 3411, 3412, 3412, 3412, 3412, 3412, 3412, 3412, 3412,
+     3412, 3412, 3412, 3412, 3412, 3413, 3413, 3413, 3413, 3413,
+     3413, 3413, 3413, 3413, 3413, 3413, 3413, 3413, 3414, 3414,
+     3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+     3414, 3415, 3415, 3415, 3415, 3415, 3415, 3415, 3415, 3415,
+     3415, 3415, 3415, 3415, 3416, 3416, 3416, 3416, 3416, 3416,
+     3416, 3416, 3416, 3416, 3416, 3416, 3416, 3417, 3417, 3417,
+     3417, 3417, 3417, 3417, 3417, 3417, 3417, 3417, 3417, 3417,
+
+     3418, 3418, 3418, 3418, 3418, 3418, 3418, 3418, 3418, 3418,
+     3418, 3418, 3418, 3419, 3419, 3419, 3419, 3419, 3419, 3419,
+     3419, 3419, 3419, 3419, 3419, 3419, 3420, 3420, 3420, 3420,
+     3420, 3420, 3420, 3420, 3420, 3420, 3420, 3420, 3420, 3421,
+     3421, 3421, 3421, 3421, 3421, 3421, 3421, 3421, 3421, 3421,
+     3421, 3421, 3422, 3422, 3422, 3422, 3422, 3422, 3422, 3422,
+     3422, 3422, 3422, 3422, 3422, 3423, 3423, 3423, 3423, 3423,
+     3423, 3423, 3423, 3423, 3423, 3423, 3423, 3423, 3424, 3424,
+     3424, 3424, 3424, 3424, 3424, 3424, 3424, 3424, 3424, 3424,
+     3424, 3425, 3425, 3425, 3425, 3425, 3425, 3425, 3425, 3425,
+
+     3425, 3425, 3425, 3425, 3426, 3426, 3426, 3426, 3426, 3426,
+     3426, 3426, 3426, 3426, 3426, 3426, 3426, 3427, 3427, 3427,
+     3427, 3427, 3427, 3427, 3427, 3427, 3427, 3427, 3427, 3427,
+     3428, 3428, 3428, 3428, 3428, 3428, 3428, 3428, 3428, 3428,
+     3428, 3428, 3428, 3429, 3429, 3429, 3429, 3429, 3429, 3429,
+     3429, 3429, 3429, 3429, 3429, 3429, 3430, 3430, 3430, 3430,
+     3430, 3430, 3430, 3430, 3430, 3430, 3430, 3430, 3430, 3431,
+     3431, 3431, 3431, 3431, 3431, 3431, 3431, 3431, 3431, 3431,
+     3431, 3431, 3432, 3432, 3432, 3432, 3432, 3432, 3432, 3432,
+     3432, 3432, 3432, 3432, 3432, 3433, 3433, 3433, 3433, 3433,
+
+     3433, 3433, 3433, 3433, 3433, 3433, 3433, 3433, 3434, 3434,
+     3434, 3434, 3434, 3434, 3434, 3434, 3434, 3434, 3434, 3434,
+     3434, 3435, 3435, 3435, 3435, 3435, 3435, 3435, 3435, 3435,
+     3435, 3435, 3435, 3435, 3436, 3436, 3436, 3436, 3436, 3436,
+     3436, 3436, 3436, 3436, 3436, 3436, 3436, 3437, 3437, 3437,
+     3437, 3437, 3437, 3437, 3437, 3437, 3437, 3437, 3437, 3437,
+     3438, 3438, 3438, 3438, 3438, 3438, 3438, 3438, 3438, 3438,
+     3438, 3438, 3438, 3439, 3439, 3439, 3439, 3439, 3439, 3439,
+     3439, 3439, 3439, 3439, 3439, 3439, 3440, 3440, 3440, 3440,
+     3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3441,
+
+     3441, 3441, 3441, 3441, 3441, 3441, 3441, 3441, 3441, 3441,
+     3441, 3441, 3442, 3442, 3442, 3442, 3442, 3442, 3442, 3442,
+     3442, 3442, 3442, 3442, 3442, 3443, 3443, 3443, 3443, 3443,
+     3443, 3443, 3443, 3443, 3443, 3443, 3443, 3443, 3444, 3444,
+     3444, 3444, 3444, 3444, 3444, 3444, 3444, 3444, 3444, 3444,
+     3444, 3445, 3445, 3445, 3445, 3445, 3445, 3445, 3445, 3445,
+     3445, 3445, 3445, 3446, 3446, 3446, 3446, 3446,    0, 3446,
+     3446, 3446, 3446, 3447, 3447, 3447, 3447, 3447, 3447, 3447,
+     3447,    0, 3447, 3447, 3447, 3447, 3448, 3448, 3448, 3448,
+     3448, 3448, 3448, 3448,    0, 3448, 3448, 3448, 3448, 3449,
+
+     3449,    0, 3449, 3449, 3449, 3449, 3449, 3449, 3449, 3449,
+     3449, 3449, 3450, 3450,    0, 3450, 3450, 3450, 3450, 3450,
+     3450, 3450, 3450, 3450, 3450, 3451, 3451, 3451, 3451, 3451,
+     3451, 3451, 3451, 3451, 3451, 3451, 3451, 3451, 3452, 3452,
+     3452, 3452, 3452, 3452, 3452, 3452,    0, 3452, 3452, 3452,
+     3452, 3453, 3453,    0, 3453, 3453, 3453, 3453, 3453, 3453,
+     3453, 3453, 3453, 3453, 3454, 3454, 3454, 3454, 3454, 3454,
+     3454, 3454, 3454, 3454, 3454, 3454, 3454, 3455, 3455, 3455,
+     3455, 3455, 3455, 3455, 3455,    0, 3455, 3455, 3455, 3455,
+     3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456,
+
+     3456, 3456, 3456, 3457, 3457, 3457, 3457, 3457, 3457, 3457,
+     3457, 3457, 3457, 3457, 3457, 3457, 3458, 3458, 3458, 3458,
+     3458, 3458, 3458, 3458,    0, 3458, 3458, 3458, 3458, 3459,
+     3459, 3459, 3459, 3459, 3459, 3459, 3459, 3459, 3459, 3459,
+     3459, 3459, 3460, 3460, 3460, 3460, 3460, 3460, 3460, 3460,
+     3460, 3460, 3460, 3460, 3460, 3461, 3461, 3461, 3461, 3461,
+     3461, 3461, 3461, 3461, 3461, 3461, 3461, 3461, 3462, 3462,
+     3462, 3462, 3462, 3462, 3462, 3462, 3462, 3462, 3462, 3462,
+     3462, 3463, 3463, 3463, 3463, 3463, 3463, 3463, 3463, 3463,
+     3463, 3463, 3463, 3463, 3464, 3464, 3464, 3464, 3464, 3464,
+
+     3464, 3464, 3464, 3464, 3464, 3464, 3464, 3465, 3465, 3465,
+     3465, 3465, 3465, 3465, 3465, 3465, 3465, 3465, 3465, 3465,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+     2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
+
+     2915, 2915, 2915, 2915, 2915
+    } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[213] =
+    {   0,
+0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 
+    1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,     };
+
+extern int interface_flex_debug;
+int interface_flex_debug = 0;
+
+static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */ \
+yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
+(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
+(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
+yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
+++(yy_lp); \
+goto find_rule; \
+}
+
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() ((yy_more_flag) = 1)
+#define YY_MORE_ADJ (yy_more_len)
+#define YY_RESTORE_YY_MORE_OFFSET
+char *interfacetext;
+#line 1 "interface.l"
+/*   Foma: a finite-state toolkit and library.                                 */
+/*   Copyright © 2008-2015 Mans Hulden                                         */
+/*   This file is part of foma.                                                */
+/*   Licensed under the Apache License, Version 2.0 (the "License");           */
+/*   you may not use this file except in compliance with the License.          */
+/*   You may obtain a copy of the License at                                   */
+/*      http://www.apache.org/licenses/LICENSE-2.0                             */
+/*   Unless required by applicable law or agreed to in writing, software       */
+/*   distributed under the License is distributed on an "AS IS" BASIS,         */
+/*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
+/*   See the License for the specific language governing permissions and       */
+/*   limitations under the License.                                            */
+#define YY_NO_INPUT 1
+
+#line 26 "interface.l"
+#include <stdio.h>
+#include "foma.h"
+#define RE 0 /* regex  */
+#define DE 1 /* define */
+
+char funcdef[16384];
+
+struct func_args {
+   char *arg; 
+   int argno;
+   struct func_args *next;
+};
+
+struct func_args *func_args = NULL;
+
+static char *func_name;
+static char *tempstr = NULL;
+static char *lexcfilein;
+static char *cmatrixfilein;
+static int pmode;
+static int func_arg_no;
+static int olddef;
+static int applydir;
+static struct fsm *tempnet;
+extern int promptmode;
+extern int apply_direction;
+extern int g_list_limit;
+
+extern int my_yyparse(char *my_string, int lineno, struct defined_networks *defined_nets, struct defined_functions *defined_funcs);
+extern void my_cmatrixparse(struct fsm *net, char *my_string);
+extern struct fsm *current_parse;
+extern struct fsm *fsm_lexc_parse_string(char *string, int verbose);
+extern int interfacelex();
+extern struct fsm *current_parse;
+extern void lexc_trim(char *s);
+
+int input_is_file;
+
+int get_iface_lineno(void) {
+  return(interfacelineno);
+}
+
+void clear_func_args(void) {
+    struct func_args *fa, *fp;  
+    for (fa = func_args; fa != NULL; ) {
+	xxfree(fa->arg);
+	fp = fa;
+	fa = fa->next;
+	xxfree(fp);
+    }
+    func_args = NULL;
+}
+
+void add_func_arg(char *s) {
+  struct func_args *fa;
+  fa = xxmalloc(sizeof(struct func_args));
+  fa->arg = xxstrdup(s);
+  fa->next = func_args;
+  fa->argno = func_arg_no;
+  func_arg_no++;
+  func_args = fa;
+}
+
+char *rep_func_arg(char *s) {
+  struct func_args *fa;  
+  char *argstr;
+  for (fa = func_args; fa != NULL; fa = fa->next) {
+    if (strcmp(fa->arg,s) == 0) {
+        argstr = xxmalloc(sizeof(char)*20);
+        sprintf(argstr, "@ARGUMENT%02i@", fa->argno);
+        return(argstr);
+    }
+  }
+  return(xxstrdup(s));
+}
+
+void my_interfaceparse(char *my_string) {
+
+   YY_BUFFER_STATE my_string_buffer;
+   my_string_buffer = interface_scan_string(my_string);
+   interfacelineno = 1;
+   func_args = NULL;
+   interfacelex();
+   //interface_delete_buffer(my_string_buffer);
+}
+
+
+#line 7839 "lex.interface.c"
+
+#define INITIAL 0
+#define REGEX 1
+#define DEFI 2
+#define DEF 3
+#define SOURCE 4
+#define APPLY_DOWN 5
+#define APPLY_FILE_IN 6
+#define APPLY_MED 7
+#define APPLY_UP 8
+#define APPLY_P 9
+#define ELIMINATE_FLAG 10
+#define UNDEFINE 11
+#define RPL 12
+#define RLEXC 13
+#define RCMATRIX 14
+#define READ_TEXT 15
+#define READ_SPACED_TEXT 16
+#define SHOW_VAR 17
+#define SET_VAR 18
+#define SET_VALUE 19
+#define SAVE_STACK 20
+#define SAVE_DEFINED 21
+#define LOAD_STACK 22
+#define LOAD_DEFINED 23
+#define IGNORELINE 24
+#define REGEXQ 25
+#define REGEXB 26
+#define PUSH 27
+#define NAME_NET 28
+#define ECHO 29
+#define SYSTEM 30
+#define FUNC_1 31
+#define FUNC_2 32
+#define FUNC_3 33
+#define FUNC_4 34
+#define APROPOS 35
+#define HELP 36
+#define PRINT_NET_FILE 37
+#define PRINT_NET_NAME 38
+#define PRINT_NET_NAME_FILE 39
+#define PRINT_NET_NAME_FILE2 40
+#define PRINT_DOT_FILE 41
+#define PRINT_DOT_NAME 42
+#define SUBSTITUTE_SYMBOL 43
+#define SUBSTITUTE_SYMBOL_2 44
+#define SUBSTITUTE_SYMBOL_3 45
+#define SUBSTITUTE_DEFINED 46
+#define SUBSTITUTE_DEFINED_2 47
+#define SUBSTITUTE_DEFINED_3 48
+#define WRITE_ATT_FILE 49
+#define WRITE_PROLOG_FILE 50
+#define RCOMMENT 51
+#define APPLY_FILE_EATUP 52
+#define APPLY_FILE_OUT 53
+#define ATT 54
+#define EXCMATRIX 55
+#define ASSERT_STACK 56
+#define WORDS_FILE 57
+#define PAIRS_FILE 58
+#define UPPER_WORDS_FILE 59
+#define LOWER_WORDS_FILE 60
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int interfacelex_destroy (void );
+
+int interfaceget_debug (void );
+
+void interfaceset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE interfaceget_extra (void );
+
+void interfaceset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *interfaceget_in (void );
+
+void interfaceset_in  (FILE * in_str  );
+
+FILE *interfaceget_out (void );
+
+void interfaceset_out  (FILE * out_str  );
+
+int interfaceget_leng (void );
+
+char *interfaceget_text (void );
+
+int interfaceget_lineno (void );
+
+void interfaceset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int interfacewrap (void );
+#else
+extern int interfacewrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( interfacetext, interfaceleng, 1, interfaceout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( interfacein )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( interfacein ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, interfacein))==0 && ferror(interfacein)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(interfacein); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int interfacelex (void);
+
+#define YY_DECL int interfacelex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after interfacetext and interfaceleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( interfaceleng > 0 ) \
+		YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+				(interfacetext[interfaceleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 132 "interface.l"
+
+ 
+  if (YY_START == APPLY_P && promptmode == PROMPT_MAIN) 
+    BEGIN(INITIAL); 
+
+
+#line 8094 "lex.interface.c"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+        /* Create the reject buffer large enough to save one state per allowed character. */
+        if ( ! (yy_state_buf) )
+            (yy_state_buf) = (yy_state_type *)interfacealloc(YY_STATE_BUF_SIZE  );
+            if ( ! (yy_state_buf) )
+                YY_FATAL_ERROR( "out of dynamic memory in interfacelex()" );
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! interfacein )
+			interfacein = stdin;
+
+		if ( ! interfaceout )
+			interfaceout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			interfaceensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				interface_create_buffer(interfacein,YY_BUF_SIZE );
+		}
+
+		interface_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		(yy_more_len) = 0;
+		if ( (yy_more_flag) )
+			{
+			(yy_more_len) = (yy_c_buf_p) - (yytext_ptr);
+			(yy_more_flag) = 0;
+			}
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of interfacetext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+		yy_current_state += YY_AT_BOL();
+
+		(yy_state_ptr) = (yy_state_buf);
+		*(yy_state_ptr)++ = yy_current_state;
+
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 2916 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			*(yy_state_ptr)++ = yy_current_state;
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 26921 );
+
+yy_find_action:
+		yy_current_state = *--(yy_state_ptr);
+		(yy_lp) = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+		for ( ; ; ) /* until we find what rule we matched */
+			{
+			if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
+				{
+				yy_act = yy_acclist[(yy_lp)];
+				if ( yy_act & YY_TRAILING_HEAD_MASK ||
+				     (yy_looking_for_trail_begin) )
+					{
+					if ( yy_act == (yy_looking_for_trail_begin) )
+						{
+						(yy_looking_for_trail_begin) = 0;
+						yy_act &= ~YY_TRAILING_HEAD_MASK;
+						break;
+						}
+					}
+				else if ( yy_act & YY_TRAILING_MASK )
+					{
+					(yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
+					(yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
+					}
+				else
+					{
+					(yy_full_match) = yy_cp;
+					(yy_full_state) = (yy_state_ptr);
+					(yy_full_lp) = (yy_lp);
+					break;
+					}
+				++(yy_lp);
+				goto find_rule;
+				}
+			--yy_cp;
+			yy_current_state = *--(yy_state_ptr);
+			(yy_lp) = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+			{
+			int yyl;
+			for ( yyl = (yy_more_len); yyl < interfaceleng; ++yyl )
+				if ( interfacetext[yyl] == '\n' )
+					   
+    interfacelineno++;
+;
+			}
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 138 "interface.l"
+{ iface_ambiguous_upper(); }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 139 "interface.l"
+{ BEGIN(APPLY_DOWN);}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 140 "interface.l"
+{ if (iface_stack_check(1)) {promptmode = PROMPT_A; apply_direction = AP_D; BEGIN(APPLY_P);}}
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 141 "interface.l"
+{ applydir = AP_D; BEGIN(APPLY_FILE_IN);}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 142 "interface.l"
+{ if (iface_stack_check(1)) {promptmode = PROMPT_A; apply_direction = AP_M; BEGIN(APPLY_P);}}
+	YY_BREAK
+case 6:
+/* rule 6 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 143 "interface.l"
+{ BEGIN(APPLY_MED);}
+	YY_BREAK
+case 7:
+/* rule 7 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 144 "interface.l"
+{ BEGIN(APPLY_UP);}
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 145 "interface.l"
+{ if (iface_stack_check(1)) {promptmode = PROMPT_A; apply_direction = AP_U; BEGIN(APPLY_P);}}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 146 "interface.l"
+{ applydir = AP_U; BEGIN(APPLY_FILE_IN);}
+	YY_BREAK
+case 10:
+/* rule 10 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 147 "interface.l"
+{BEGIN(APROPOS); }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 148 "interface.l"
+{BEGIN(ASSERT_STACK);}
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 149 "interface.l"
+{  stack_clear();}
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 150 "interface.l"
+{  iface_close();}
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 151 "interface.l"
+{ iface_compact(); }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 152 "interface.l"
+{ iface_complete();}
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 153 "interface.l"
+{ iface_compose();}
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 154 "interface.l"
+{iface_conc();}
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 155 "interface.l"
+{ iface_crossproduct();}
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 156 "interface.l"
+{ pmode = DE; BEGIN(DEFI); }
+	YY_BREAK
+case 20:
+/* rule 20 can match eol */
+YY_RULE_SETUP
+#line 157 "interface.l"
+{ pmode = DE; lexc_trim(interfacetext); tempstr = xxstrdup(interfacetext); BEGIN(REGEX); }
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 158 "interface.l"
+{ iface_determinize(); }
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 159 "interface.l"
+{ BEGIN(ECHO); }
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 160 "interface.l"
+{ printf("\n"); }
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 161 "interface.l"
+{ iface_eliminate_flags(); }
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 162 "interface.l"
+{ BEGIN(ELIMINATE_FLAG); }
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 163 "interface.l"
+{ iface_print_cmatrix_att(NULL); }
+	YY_BREAK
+case 27:
+/* rule 27 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 164 "interface.l"
+{ BEGIN(EXCMATRIX);          }
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 165 "interface.l"
+{ iface_extract_ambiguous(); }
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 166 "interface.l"
+{ iface_extract_unambiguous(); }
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 167 "interface.l"
+{ iface_factorize(); }
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 168 "interface.l"
+{ iface_sequentialize(); }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 169 "interface.l"
+{ iface_warranty(); }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 170 "interface.l"
+{ iface_help(); }
+	YY_BREAK
+case 34:
+/* rule 34 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 171 "interface.l"
+{ BEGIN(HELP); }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 172 "interface.l"
+{ iface_ignore(); }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 173 "interface.l"
+{ iface_intersect();}
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 174 "interface.l"
+{ iface_invert(); }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 175 "interface.l"
+{ iface_label_net(); }
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 176 "interface.l"
+{ iface_letter_machine(); }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 177 "interface.l"
+{ BEGIN(LOAD_DEFINED); }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 178 "interface.l"
+{ BEGIN(LOAD_STACK); }
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 179 "interface.l"
+{  iface_lower_side();}
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 180 "interface.l"
+{ iface_minimize(); }
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 181 "interface.l"
+{ BEGIN(NAME_NET); }
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 182 "interface.l"
+{ iface_negate(); }
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 183 "interface.l"
+{ iface_one_plus();}
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 184 "interface.l"
+{ iface_pop();}
+	YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 185 "interface.l"
+{ iface_print_cmatrix(); }
+	YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 186 "interface.l"
+{ iface_print_defined(); }
+	YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 187 "interface.l"
+{ iface_print_dot(NULL); }
+	YY_BREAK
+case 51:
+/* rule 51 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 188 "interface.l"
+{ BEGIN(PRINT_DOT_FILE); }
+	YY_BREAK
+case 52:
+/* rule 52 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 189 "interface.l"
+{ BEGIN(PRINT_DOT_NAME); }
+	YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 190 "interface.l"
+{ iface_lower_words(-1); }
+	YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 191 "interface.l"
+{ iface_lower_words(iface_extract_number(interfacetext)); }
+	YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 192 "interface.l"
+{ iface_print_name(); }
+	YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 193 "interface.l"
+{ iface_print_net(NULL,NULL); }
+	YY_BREAK
+case 57:
+/* rule 57 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 194 "interface.l"
+{ BEGIN(PRINT_NET_FILE);      }
+	YY_BREAK
+case 58:
+/* rule 58 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 195 "interface.l"
+{ BEGIN(PRINT_NET_NAME);      }
+	YY_BREAK
+case 59:
+/* rule 59 can match eol */
+YY_RULE_SETUP
+#line 196 "interface.l"
+{ BEGIN(PRINT_NET_NAME_FILE); }
+	YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 197 "interface.l"
+{ iface_random_lower(-1); }
+	YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 198 "interface.l"
+{ iface_random_lower(iface_extract_number(interfacetext)); }
+	YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 199 "interface.l"
+{ iface_random_upper(-1); }
+	YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 200 "interface.l"
+{ iface_random_upper(iface_extract_number(interfacetext)); }
+	YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 201 "interface.l"
+{ iface_random_words(-1); }
+	YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 202 "interface.l"
+{ iface_random_words(iface_extract_number(interfacetext)); }
+	YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 203 "interface.l"
+{ iface_print_sigma(); }
+	YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 204 "interface.l"
+{ iface_print_stats(); }
+	YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 205 "interface.l"
+{ printf("STACK SIZE: %d\n", stack_size()); }
+	YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 206 "interface.l"
+{ iface_upper_words(-1); }
+	YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 207 "interface.l"
+{ iface_upper_words(iface_extract_number(interfacetext)); }
+	YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 208 "interface.l"
+{ iface_pairs(-1);}
+	YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 209 "interface.l"
+{ iface_random_pairs(-1);}
+	YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 210 "interface.l"
+{ iface_words(-1);}
+	YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 211 "interface.l"
+{ iface_words(iface_extract_number(interfacetext));}
+	YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 212 "interface.l"
+{ BEGIN(WORDS_FILE); }
+	YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 213 "interface.l"
+{ BEGIN(PAIRS_FILE); }
+	YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 214 "interface.l"
+{ BEGIN(LOWER_WORDS_FILE); }
+	YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 215 "interface.l"
+{ BEGIN(UPPER_WORDS_FILE); }
+	YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 216 "interface.l"
+{ iface_print_shortest_string();}
+	YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 217 "interface.l"
+{ iface_print_shortest_string_size();}
+	YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 218 "interface.l"
+{ iface_prune(); }
+	YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 219 "interface.l"
+{ BEGIN(PUSH); }
+	YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 220 "interface.l"
+{ iface_quit(); }
+	YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 221 "interface.l"
+{ BEGIN(ATT); }
+	YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 222 "interface.l"
+{ printf("Missing filename.\n"); }
+	YY_BREAK
+case 86:
+/* rule 86 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 223 "interface.l"
+{ BEGIN(RCMATRIX); }
+	YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 224 "interface.l"
+{ BEGIN(RPL); }
+	YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 225 "interface.l"
+{ BEGIN(RLEXC); }
+	YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 226 "interface.l"
+{ pmode = RE; BEGIN(REGEX); }
+	YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 227 "interface.l"
+{ BEGIN(READ_SPACED_TEXT); }
+	YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 228 "interface.l"
+{ BEGIN(READ_TEXT); }
+	YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 229 "interface.l"
+{ iface_reverse(); }
+	YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 230 "interface.l"
+{ iface_rotate();}
+	YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 231 "interface.l"
+{ BEGIN(SAVE_DEFINED); }
+	YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 232 "interface.l"
+{ BEGIN(SAVE_STACK); }
+	YY_BREAK
+case 96:
+/* rule 96 can match eol */
+YY_RULE_SETUP
+#line 233 "interface.l"
+{ BEGIN(SET_VAR); }
+	YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 234 "interface.l"
+{ iface_show_variables();}
+	YY_BREAK
+case 98:
+/* rule 98 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 235 "interface.l"
+{ BEGIN(SHOW_VAR); }
+	YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 236 "interface.l"
+{ iface_shuffle(); }
+	YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 237 "interface.l"
+{ iface_sigma_net(); }
+	YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 238 "interface.l"
+{ iface_sort_input(); }
+	YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 239 "interface.l"
+{ iface_sort_output(); }
+	YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 240 "interface.l"
+{ iface_sort(); }
+	YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 241 "interface.l"
+{BEGIN(SOURCE);}
+	YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 242 "interface.l"
+{BEGIN(SUBSTITUTE_DEFINED);}
+	YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 243 "interface.l"
+{BEGIN(SUBSTITUTE_SYMBOL);}
+	YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 244 "interface.l"
+{BEGIN(SYSTEM);}
+	YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 245 "interface.l"
+{  iface_test_unambiguous(); }
+	YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 246 "interface.l"
+{  iface_test_equivalent(); }
+	YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 247 "interface.l"
+{  iface_test_functional(); }
+	YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 248 "interface.l"
+{  iface_test_identity(); }
+	YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 249 "interface.l"
+{  iface_test_nonnull(); }
+	YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 250 "interface.l"
+{  iface_test_null(); }
+	YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 251 "interface.l"
+{  iface_test_lower_universal(); }
+	YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 252 "interface.l"
+{  iface_test_sequential(); }
+	YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 253 "interface.l"
+{  iface_test_upper_universal(); }
+	YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 254 "interface.l"
+{  iface_turn(); }
+	YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 255 "interface.l"
+{  iface_twosided_flags(); }
+	YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 256 "interface.l"
+{BEGIN(UNDEFINE);}
+	YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 257 "interface.l"
+{iface_union();}
+	YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 258 "interface.l"
+{ iface_upper_side(); }
+	YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 259 "interface.l"
+{ iface_view(); }
+	YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 260 "interface.l"
+{ iface_write_prolog(NULL); }
+	YY_BREAK
+case 124:
+/* rule 124 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 261 "interface.l"
+{ BEGIN(WRITE_PROLOG_FILE); }
+	YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 262 "interface.l"
+{ iface_write_att(NULL); }
+	YY_BREAK
+case 126:
+/* rule 126 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 263 "interface.l"
+{ BEGIN(WRITE_ATT_FILE); }
+	YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 264 "interface.l"
+{ iface_zero_plus(); }
+	YY_BREAK
+case 128:
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 266 "interface.l"
+{
+   tempstr = trim(xxstrdup(interfacetext));
+   BEGIN(APPLY_FILE_EATUP);
+}
+	YY_BREAK
+case 129:
+/* rule 129 can match eol */
+YY_RULE_SETUP
+#line 271 "interface.l"
+{
+   iface_apply_file(trim(interfacetext),NULL, applydir);
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 275 "interface.l"
+{
+  BEGIN(APPLY_FILE_OUT);
+}
+	YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 278 "interface.l"
+{
+  iface_apply_file(tempstr, trim(interfacetext), applydir);
+  xxfree(tempstr);
+  tempstr = NULL;
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 285 "interface.l"
+{
+   iface_apply_down(interfacetext);
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 289 "interface.l"
+{
+   iface_apply_down(interfacetext);
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 293 "interface.l"
+{
+   iface_apply_med(interfacetext);
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 297 "interface.l"
+{
+   iface_apply_up(interfacetext);
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 301 "interface.l"
+{
+  iface_name_net(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 306 "interface.l"
+{
+  iface_help_search(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 310 "interface.l"
+{
+  iface_apropos(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 315 "interface.l"
+{
+    if (find_defined(g_defines, interfacetext) == NULL)
+	printf("'%s' is not a defined symbol.\n",interfacetext);
+    else
+	stack_add(fsm_copy(find_defined(g_defines, interfacetext)));
+    BEGIN(INITIAL);
+}
+	YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 323 "interface.l"
+{
+  if (strcmp(interfacetext,"END;") == 0) {
+    promptmode = PROMPT_MAIN;
+    BEGIN(INITIAL);
+  } else {
+     if (apply_direction == AP_D)
+       iface_apply_down(interfacetext);
+
+     if (apply_direction == AP_M)
+       iface_apply_med(interfacetext);
+
+     if (apply_direction == AP_U)
+       iface_apply_up(interfacetext);
+  }
+}
+	YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 340 "interface.l"
+{ yymore(); BEGIN(RCOMMENT); }
+	YY_BREAK
+case 142:
+YY_RULE_SETUP
+#line 342 "interface.l"
+{ }
+	YY_BREAK
+case 143:
+YY_RULE_SETUP
+#line 344 "interface.l"
+{ yymore();}
+	YY_BREAK
+case 144:
+/* rule 144 can match eol */
+YY_RULE_SETUP
+#line 346 "interface.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 145:
+/* rule 145 can match eol */
+YY_RULE_SETUP
+#line 350 "interface.l"
+{ yymore(); BEGIN(REGEX); }
+	YY_BREAK
+case 146:
+/* rule 146 can match eol */
+YY_RULE_SETUP
+#line 351 "interface.l"
+{ yymore(); }
+	YY_BREAK
+case 147:
+YY_RULE_SETUP
+#line 353 "interface.l"
+{
+    if (my_yyparse(interfacetext, interfacelineno, g_defines, g_defines_f) == 0) {
+      /* regex xxx line */
+      if (pmode == RE) {
+         stack_add(fsm_topsort(fsm_minimize(current_parse)));
+      /* define XXX xxx line */
+      } else if (pmode == DE) {
+        tempnet = fsm_topsort(fsm_minimize(current_parse));
+        olddef = add_defined(g_defines, tempnet,tempstr);
+        if (olddef) {
+          printf("redefined %s: ",tempstr);
+        } else {
+          printf("defined %s: ",tempstr);
+        }
+        print_stats(tempnet);
+        xxfree(tempstr);
+        tempstr = NULL;
+      }
+    }
+    BEGIN(INITIAL);
+}
+	YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 374 "interface.l"
+{
+  BEGIN(REGEXB);
+  yymore();
+}
+	YY_BREAK
+case 149:
+/* rule 149 can match eol */
+YY_RULE_SETUP
+#line 378 "interface.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 381 "interface.l"
+{
+  BEGIN(REGEX);
+  yymore();
+}
+	YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 385 "interface.l"
+{
+  BEGIN(REGEXQ);
+  yymore();
+}
+	YY_BREAK
+case 152:
+/* rule 152 can match eol */
+YY_RULE_SETUP
+#line 389 "interface.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 392 "interface.l"
+{
+  BEGIN(REGEX);
+  yymore();
+}
+	YY_BREAK
+case 154:
+/* rule 154 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up interfacetext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up interfacetext again */
+YY_RULE_SETUP
+#line 397 "interface.l"
+{
+   func_name = xxmalloc(sizeof(char)*(strlen(interfacetext)+2));
+   func_name = strcpy(func_name, interfacetext);
+   strcat(func_name, "(");
+   func_arg_no = 1;
+   BEGIN(FUNC_1);
+}
+	YY_BREAK
+/* Eat up parenthesis */
+case 155:
+YY_RULE_SETUP
+#line 406 "interface.l"
+{ BEGIN(FUNC_2); }
+	YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 408 "interface.l"
+{ }
+	YY_BREAK
+case 157:
+/* rule 157 can match eol */
+YY_RULE_SETUP
+#line 409 "interface.l"
+{
+  add_func_arg(interfacetext);
+}
+	YY_BREAK
+case 158:
+/* rule 158 can match eol */
+YY_RULE_SETUP
+#line 412 "interface.l"
+{
+  add_func_arg(interfacetext);
+  BEGIN(FUNC_3);
+}
+	YY_BREAK
+case 159:
+YY_RULE_SETUP
+#line 417 "interface.l"
+{ funcdef[0] = '\0'; BEGIN(FUNC_4); }
+	YY_BREAK
+case 160:
+/* rule 160 can match eol */
+YY_RULE_SETUP
+#line 418 "interface.l"
+{ tempstr = rep_func_arg(interfacetext); strcat(funcdef, tempstr); xxfree(tempstr); tempstr = NULL;}
+	YY_BREAK
+case 161:
+/* rule 161 can match eol */
+YY_RULE_SETUP
+#line 419 "interface.l"
+{ strcat(funcdef, interfacetext); }
+	YY_BREAK
+case 162:
+/* rule 162 can match eol */
+YY_RULE_SETUP
+#line 420 "interface.l"
+{ strcat(funcdef, interfacetext); }
+	YY_BREAK
+case 163:
+/* rule 163 can match eol */
+YY_RULE_SETUP
+#line 421 "interface.l"
+{ strcat(funcdef, interfacetext); }
+	YY_BREAK
+case 164:
+YY_RULE_SETUP
+#line 422 "interface.l"
+{ strcat(funcdef, interfacetext); add_defined_function(g_defines_f, func_name, funcdef, (func_arg_no-1));clear_func_args(); xxfree(func_name); BEGIN(INITIAL); }
+	YY_BREAK
+case 165:
+YY_RULE_SETUP
+#line 423 "interface.l"
+{ strcat(funcdef, interfacetext); }
+	YY_BREAK
+case 166:
+YY_RULE_SETUP
+#line 426 "interface.l"
+{
+  tempstr = xxstrdup(interfacetext);
+  BEGIN(REGEX);
+}
+	YY_BREAK
+case 167:
+YY_RULE_SETUP
+#line 431 "interface.l"
+{
+
+   tempnet = NULL;
+   /* Define the top network on stack */
+   if (iface_stack_check(1)) {
+       tempnet = stack_pop();
+       olddef = add_defined(g_defines, tempnet,remove_trailing(interfacetext,';'));
+       if (olddef) {
+         printf("redefined %s: ",interfacetext);
+       } else {
+          printf("defined %s: ",interfacetext);
+       }
+       print_stats(tempnet);
+     }
+     BEGIN(INITIAL);
+}
+	YY_BREAK
+case 168:
+YY_RULE_SETUP
+#line 448 "interface.l"
+{
+    remove_defined(g_defines, remove_trailing(interfacetext,';'));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 169:
+YY_RULE_SETUP
+#line 453 "interface.l"
+{
+  iface_print_net(NULL,trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 170:
+YY_RULE_SETUP
+#line 457 "interface.l"
+{
+  iface_print_net(trim(interfacetext), NULL);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 171:
+/* rule 171 can match eol */
+YY_RULE_SETUP
+#line 461 "interface.l"
+{
+  tempstr = xxstrdup(trim(interfacetext));
+  BEGIN(PRINT_NET_NAME_FILE2);
+}
+	YY_BREAK
+case 172:
+YY_RULE_SETUP
+#line 465 "interface.l"
+{ }
+	YY_BREAK
+case 173:
+/* rule 173 can match eol */
+YY_RULE_SETUP
+#line 466 "interface.l"
+{ 
+  iface_print_net(tempstr, trim(interfacetext));  
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 174:
+YY_RULE_SETUP
+#line 470 "interface.l"
+{
+  iface_write_att(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 175:
+YY_RULE_SETUP
+#line 475 "interface.l"
+{
+  iface_write_prolog(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 176:
+YY_RULE_SETUP
+#line 480 "interface.l"
+{
+  iface_print_dot(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 177:
+YY_RULE_SETUP
+#line 485 "interface.l"
+{
+  if ((interfacein = fopen(trim(interfacetext), "r" )) != NULL) {
+    printf("Opening file '%s'.\n", trim(interfacetext));    
+    input_is_file = 1;
+    interfacepush_buffer_state(interface_create_buffer(interfacein,YY_BUF_SIZE*2));
+  } else {
+    printf("Error opening file '%s'\n",trim(interfacetext));
+  }
+  BEGIN(INITIAL); 
+}
+	YY_BREAK
+case 178:
+YY_RULE_SETUP
+#line 496 "interface.l"
+{
+  iface_show_variable(interfacetext);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 179:
+/* rule 179 can match eol */
+YY_RULE_SETUP
+#line 500 "interface.l"
+{
+  tempstr = xxstrdup(interfacetext);
+  BEGIN(SET_VALUE);
+}
+	YY_BREAK
+case 180:
+YY_RULE_SETUP
+#line 504 "interface.l"
+{
+  iface_set_variable(tempstr,interfacetext);
+  xxfree(tempstr);
+  tempstr = NULL;
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 181:
+YY_RULE_SETUP
+#line 510 "interface.l"
+{ }
+	YY_BREAK
+case 182:
+YY_RULE_SETUP
+#line 512 "interface.l"
+{
+  iface_read_spaced_text(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 183:
+YY_RULE_SETUP
+#line 517 "interface.l"
+{
+  iface_read_text(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 184:
+YY_RULE_SETUP
+#line 522 "interface.l"
+{
+  iface_words_file(trim(interfacetext),0);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 185:
+YY_RULE_SETUP
+#line 527 "interface.l"
+{
+  iface_pairs_file(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 186:
+YY_RULE_SETUP
+#line 532 "interface.l"
+{
+  iface_words_file(trim(interfacetext),1);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 187:
+YY_RULE_SETUP
+#line 537 "interface.l"
+{
+  iface_words_file(trim(interfacetext),2);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 188:
+YY_RULE_SETUP
+#line 543 "interface.l"
+{
+  iface_save_defined(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 189:
+YY_RULE_SETUP
+#line 547 "interface.l"
+{
+  iface_save_stack(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 190:
+YY_RULE_SETUP
+#line 551 "interface.l"
+{
+  iface_load_stack(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 191:
+YY_RULE_SETUP
+#line 555 "interface.l"
+{
+  iface_load_defined(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 192:
+/* rule 192 can match eol */
+YY_RULE_SETUP
+#line 559 "interface.l"
+{ tempstr = xxstrdup(interfacetext); BEGIN(SUBSTITUTE_SYMBOL_2);}
+	YY_BREAK
+case 193:
+YY_RULE_SETUP
+#line 560 "interface.l"
+{BEGIN(SUBSTITUTE_SYMBOL_3);}
+	YY_BREAK
+case 194:
+YY_RULE_SETUP
+#line 561 "interface.l"
+{
+  iface_substitute_symbol(interfacetext, tempstr); 
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 195:
+/* rule 195 can match eol */
+YY_RULE_SETUP
+#line 565 "interface.l"
+{ tempstr = xxstrdup(interfacetext); BEGIN(SUBSTITUTE_DEFINED_2);}
+	YY_BREAK
+case 196:
+YY_RULE_SETUP
+#line 566 "interface.l"
+{BEGIN(SUBSTITUTE_DEFINED_3);}
+	YY_BREAK
+case 197:
+YY_RULE_SETUP
+#line 567 "interface.l"
+{
+  iface_substitute_defined(interfacetext, tempstr); 
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 198:
+YY_RULE_SETUP
+#line 572 "interface.l"
+{
+  iface_eliminate_flag(interfacetext);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 199:
+YY_RULE_SETUP
+#line 577 "interface.l"
+{
+  int ret;
+  ret = system(interfacetext);
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 200:
+YY_RULE_SETUP
+#line 583 "interface.l"
+{
+    printf("%s\n",interfacetext);
+    BEGIN(INITIAL);
+}
+	YY_BREAK
+case 201:
+YY_RULE_SETUP
+#line 588 "interface.l"
+{
+    int level = strtoul(interfacetext, 0, 10);
+    if (level != stack_size()) {
+      fprintf(stderr, "Stack size %d not %d\n", stack_size(), level);
+      exit(1);
+    }
+    BEGIN(INITIAL);
+}
+	YY_BREAK
+case 202:
+YY_RULE_SETUP
+#line 597 "interface.l"
+{
+  iface_read_att(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 203:
+YY_RULE_SETUP
+#line 602 "interface.l"
+{
+  iface_read_prolog(trim(interfacetext));
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 204:
+YY_RULE_SETUP
+#line 607 "interface.l"
+{
+  if ((lexcfilein = file_to_mem(trim(interfacetext))) != NULL) {
+     stack_add(fsm_lexc_parse_string(lexcfilein, 1));
+     xxfree(lexcfilein); 
+  } else {
+    printf("Error opening file '%s'.\n", interfacetext);
+  }
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 205:
+YY_RULE_SETUP
+#line 617 "interface.l"
+{
+   iface_print_cmatrix_att(trim(interfacetext));
+   BEGIN(INITIAL);
+}
+	YY_BREAK
+case 206:
+YY_RULE_SETUP
+#line 622 "interface.l"
+{
+  if (iface_stack_check(1)) {
+    if ((cmatrixfilein = file_to_mem(trim(interfacetext))) != NULL) {
+       printf("Reading confusion matrix from file '%s'\n",interfacetext);
+       my_cmatrixparse(stack_find_top()->fsm, cmatrixfilein);
+       xxfree(cmatrixfilein);
+    } else {
+      perror("File error");
+    }
+  }
+  BEGIN(INITIAL);
+}
+	YY_BREAK
+case 207:
+YY_RULE_SETUP
+#line 635 "interface.l"
+{ }
+	YY_BREAK
+case 208:
+/* rule 208 can match eol */
+YY_RULE_SETUP
+#line 637 "interface.l"
+{ }
+	YY_BREAK
+case 209:
+YY_RULE_SETUP
+#line 638 "interface.l"
+{ }
+	YY_BREAK
+case 210:
+/* rule 210 can match eol */
+YY_RULE_SETUP
+#line 640 "interface.l"
+{
+      if (!input_is_file)
+        printf("Unknown command. Ignoring until end of line.\n");
+      else 
+        printf("***Unknown command '%s' on line %i. Aborting.\n",interfacetext,interfacelineno);
+      return 1;
+}
+	YY_BREAK
+case 211:
+YY_RULE_SETUP
+#line 648 "interface.l"
+{ BEGIN(INITIAL);  }
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(REGEX):
+case YY_STATE_EOF(DEFI):
+case YY_STATE_EOF(DEF):
+case YY_STATE_EOF(SOURCE):
+case YY_STATE_EOF(APPLY_DOWN):
+case YY_STATE_EOF(APPLY_FILE_IN):
+case YY_STATE_EOF(APPLY_MED):
+case YY_STATE_EOF(APPLY_UP):
+case YY_STATE_EOF(APPLY_P):
+case YY_STATE_EOF(ELIMINATE_FLAG):
+case YY_STATE_EOF(UNDEFINE):
+case YY_STATE_EOF(RPL):
+case YY_STATE_EOF(RLEXC):
+case YY_STATE_EOF(RCMATRIX):
+case YY_STATE_EOF(READ_TEXT):
+case YY_STATE_EOF(READ_SPACED_TEXT):
+case YY_STATE_EOF(SHOW_VAR):
+case YY_STATE_EOF(SET_VAR):
+case YY_STATE_EOF(SET_VALUE):
+case YY_STATE_EOF(SAVE_STACK):
+case YY_STATE_EOF(SAVE_DEFINED):
+case YY_STATE_EOF(LOAD_STACK):
+case YY_STATE_EOF(LOAD_DEFINED):
+case YY_STATE_EOF(IGNORELINE):
+case YY_STATE_EOF(REGEXQ):
+case YY_STATE_EOF(REGEXB):
+case YY_STATE_EOF(PUSH):
+case YY_STATE_EOF(NAME_NET):
+case YY_STATE_EOF(ECHO):
+case YY_STATE_EOF(SYSTEM):
+case YY_STATE_EOF(FUNC_1):
+case YY_STATE_EOF(FUNC_2):
+case YY_STATE_EOF(FUNC_3):
+case YY_STATE_EOF(FUNC_4):
+case YY_STATE_EOF(APROPOS):
+case YY_STATE_EOF(HELP):
+case YY_STATE_EOF(PRINT_NET_FILE):
+case YY_STATE_EOF(PRINT_NET_NAME):
+case YY_STATE_EOF(PRINT_NET_NAME_FILE):
+case YY_STATE_EOF(PRINT_NET_NAME_FILE2):
+case YY_STATE_EOF(PRINT_DOT_FILE):
+case YY_STATE_EOF(PRINT_DOT_NAME):
+case YY_STATE_EOF(SUBSTITUTE_SYMBOL):
+case YY_STATE_EOF(SUBSTITUTE_SYMBOL_2):
+case YY_STATE_EOF(SUBSTITUTE_SYMBOL_3):
+case YY_STATE_EOF(SUBSTITUTE_DEFINED):
+case YY_STATE_EOF(SUBSTITUTE_DEFINED_2):
+case YY_STATE_EOF(SUBSTITUTE_DEFINED_3):
+case YY_STATE_EOF(WRITE_ATT_FILE):
+case YY_STATE_EOF(WRITE_PROLOG_FILE):
+case YY_STATE_EOF(RCOMMENT):
+case YY_STATE_EOF(APPLY_FILE_EATUP):
+case YY_STATE_EOF(APPLY_FILE_OUT):
+case YY_STATE_EOF(ATT):
+case YY_STATE_EOF(EXCMATRIX):
+case YY_STATE_EOF(ASSERT_STACK):
+case YY_STATE_EOF(WORDS_FILE):
+case YY_STATE_EOF(PAIRS_FILE):
+case YY_STATE_EOF(UPPER_WORDS_FILE):
+case YY_STATE_EOF(LOWER_WORDS_FILE):
+#line 650 "interface.l"
+{
+    interfacepop_buffer_state();
+    if (!YY_CURRENT_BUFFER) {
+	yyterminate();
+    }
+}
+	YY_BREAK
+case 212:
+YY_RULE_SETUP
+#line 656 "interface.l"
+ECHO;
+	YY_BREAK
+#line 9690 "lex.interface.c"
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed interfacein at a new source and called
+			 * interfacelex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = interfacein;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( interfacewrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * interfacetext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of interfacelex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			interfacerestart(interfacein  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) interfacerealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+	yy_current_state += YY_AT_BOL();
+
+	(yy_state_ptr) = (yy_state_buf);
+	*(yy_state_ptr)++ = yy_current_state;
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 84);
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 2916 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		*(yy_state_ptr)++ = yy_current_state;
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	register YY_CHAR yy_c = 84;
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 2916 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 2915);
+	if ( ! yy_is_jam )
+		*(yy_state_ptr)++ = yy_current_state;
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					interfacerestart(interfacein );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( interfacewrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve interfacetext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+		   
+    interfacelineno++;
+;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void interfacerestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        interfaceensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            interface_create_buffer(interfacein,YY_BUF_SIZE );
+	}
+
+	interface_init_buffer(YY_CURRENT_BUFFER,input_file );
+	interface_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void interface_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		interfacepop_buffer_state();
+	 *		interfacepush_buffer_state(new_buffer);
+     */
+	interfaceensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	interface_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (interfacewrap()) processing, but the only time this flag
+	 * is looked at is after interfacewrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void interface_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	interfacein = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE interface_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) interfacealloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in interface_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) interfacealloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in interface_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	interface_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with interface_create_buffer()
+ * 
+ */
+    void interface_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		interfacefree((void *) b->yy_ch_buf  );
+
+	interfacefree((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a interfacerestart() or at EOF.
+ */
+    static void interface_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	interface_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then interface_init_buffer was _probably_
+     * called from interfacerestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void interface_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		interface_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void interfacepush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	interfaceensure_buffer_stack();
+
+	/* This block is copied from interface_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from interface_switch_to_buffer. */
+	interface_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void interfacepop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	interface_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		interface_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void interfaceensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)interfacealloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in interfaceensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)interfacerealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in interfaceensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE interface_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) interfacealloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in interface_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	interface_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to interfacelex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       interface_scan_bytes() instead.
+ */
+YY_BUFFER_STATE interface_scan_string (yyconst char * yystr )
+{
+    
+	return interface_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to interfacelex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE interface_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) interfacealloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in interface_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = interface_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in interface_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up interfacetext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		interfacetext[interfaceleng] = (yy_hold_char); \
+		(yy_c_buf_p) = interfacetext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		interfaceleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int interfaceget_lineno  (void)
+{
+        
+    return interfacelineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *interfaceget_in  (void)
+{
+        return interfacein;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *interfaceget_out  (void)
+{
+        return interfaceout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int interfaceget_leng  (void)
+{
+        return interfaceleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *interfaceget_text  (void)
+{
+        return interfacetext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void interfaceset_lineno (int  line_number )
+{
+    
+    interfacelineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see interface_switch_to_buffer
+ */
+void interfaceset_in (FILE *  in_str )
+{
+        interfacein = in_str ;
+}
+
+void interfaceset_out (FILE *  out_str )
+{
+        interfaceout = out_str ;
+}
+
+int interfaceget_debug  (void)
+{
+        return interface_flex_debug;
+}
+
+void interfaceset_debug (int  bdebug )
+{
+        interface_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from interfacelex_destroy(), so don't allocate here.
+     */
+
+    /* We do not touch interfacelineno unless the option is enabled. */
+    interfacelineno =  1;
+    
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+    (yy_state_buf) = 0;
+    (yy_state_ptr) = 0;
+    (yy_full_match) = 0;
+    (yy_lp) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    interfacein = stdin;
+    interfaceout = stdout;
+#else
+    interfacein = (FILE *) 0;
+    interfaceout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * interfacelex_init()
+     */
+    return 0;
+}
+
+/* interfacelex_destroy is for both reentrant and non-reentrant scanners. */
+int interfacelex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		interface_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		interfacepop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	interfacefree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    interfacefree ( (yy_state_buf) );
+    (yy_state_buf)  = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * interfacelex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *interfacealloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *interfacerealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void interfacefree (void * ptr )
+{
+	free( (char *) ptr );	/* see interfacerealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 656 "interface.l"
diff --git a/back-ends/foma/cpp-version/lex.lexc.cc b/back-ends/foma/cpp-version/lex.lexc.cc
new file mode 100644
index 0000000..e805748
--- /dev/null
+++ b/back-ends/foma/cpp-version/lex.lexc.cc
@@ -0,0 +1,2934 @@
+#line 22 "lexc.l"
+#define YY_BUF_SIZE 16777216
+
+
+
+#line 7 "lex.lexc.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer lexc_create_buffer
+#define yy_delete_buffer lexc_delete_buffer
+#define yy_flex_debug lexc_flex_debug
+#define yy_init_buffer lexc_init_buffer
+#define yy_flush_buffer lexc_flush_buffer
+#define yy_load_buffer_state lexc_load_buffer_state
+#define yy_switch_to_buffer lexc_switch_to_buffer
+#define yyin lexcin
+#define yyleng lexcleng
+#define yylex lexclex
+#define yylineno lexclineno
+#define yyout lexcout
+#define yyrestart lexcrestart
+#define yytext lexctext
+#define yywrap lexcwrap
+#define yyalloc lexcalloc
+#define yyrealloc lexcrealloc
+#define yyfree lexcfree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE lexcrestart(lexcin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int lexcleng;
+
+extern FILE *lexcin, *lexcout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up lexctext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up lexctext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via lexcrestart()), so that the user can continue scanning by
+	 * just pointing lexcin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when lexctext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int lexcleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow lexcwrap()'s to do buffer switches
+ * instead of setting up a fresh lexcin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void lexcrestart (FILE *input_file  );
+void lexc_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE lexc_create_buffer (FILE *file,int size  );
+void lexc_delete_buffer (YY_BUFFER_STATE b  );
+void lexc_flush_buffer (YY_BUFFER_STATE b  );
+void lexcpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void lexcpop_buffer_state (void );
+
+static void lexcensure_buffer_stack (void );
+static void lexc_load_buffer_state (void );
+static void lexc_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER lexc_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE lexc_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE lexc_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE lexc_scan_bytes (yyconst char *bytes,int len  );
+
+void *lexcalloc (yy_size_t  );
+void *lexcrealloc (void *,yy_size_t  );
+void lexcfree (void *  );
+
+#define yy_new_buffer lexc_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        lexcensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            lexc_create_buffer(lexcin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        lexcensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            lexc_create_buffer(lexcin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define lexcwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *lexcin = (FILE *) 0, *lexcout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int lexclineno;
+
+int lexclineno = 1;
+
+extern char *lexctext;
+#define yytext_ptr lexctext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up lexctext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	(yytext_ptr) -= (yy_more_len); \
+	lexcleng = (size_t) (yy_cp - (yytext_ptr)); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 31
+#define YY_END_OF_BUFFER 32
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_acclist[654] =
+    {   0,
+        3,   17,    3,   17,   18,   18,   22,   26,   22,   26,
+       27,   27,   32,   30,   31,    4,   30,   31,    5,   31,
+       30,   31,   30,   31,   30,   31,   30,   31,   30,   31,
+        6,   30,   31,   30,   31,    6,   30,   31,    6,   30,
+       31,    6,   30,   31,   30,   31,   30,   31,   30,   31,
+       30,   31,   30,   31,   30,   31,   30,   31,   30,   31,
+       30,   31,   30,   31,   30,   31,   10,   30,   31,   30,
+       31,   12,   30,   31,   10,   30,   31,   10,   30,   31,
+       10,   30,   31,   30,   31,   30,   31,   30,   31,    3,
+       30,   31,    3,    4,   30,   31,    3,    5,   31,    3,
+
+       30,   31,    3,   30,   31,   17,   30,   31,   30,   31,
+        3,   30,   31,    3,   30,   31,   13,   30,   31,    3,
+       30,   31,    3,   30,   31,    3,   30,   31,    3,   30,
+       31,   14,   30,   31,   30,   31,   30,   31,   30,   31,
+       15,   30,   31,    4,   15,   30,   31,    5,   15,   31,
+       15,   30,   31,   15,   30,   31,   15,   30,   31,   15,
+       30,   31,   15,   30,   31,   16,   30,   31,   18,   30,
+       31,    4,   18,   30,   31,    5,   18,   31,   18,   30,
+       31,   18,   30,   31,   19,   30,   31,   18,   30,   31,
+       18,   30,   31,   18,   30,   31,   22,   30,   31,    4,
+
+       22,   30,   31,    5,   22,   31,   22,   30,   31,   22,
+       30,   31,   26,   30,   31,   30,   31,   21,   30,   31,
+       22,   30,   31,   22,   30,   31,   22,   30,   31,   23,
+       30,   31,   30,   31,   30,   31,   30,   31,   24,   30,
+       31,    4,   24,   30,   31,    5,   24,   31,   24,   30,
+       31,   24,   30,   31,   24,   30,   31,   24,   30,   31,
+       24,   30,   31,   25,   30,   31,   27,   30,   31,    4,
+       27,   30,   31,    5,   27,   31,   27,   30,   31,   27,
+       30,   31,   28,   30,   31,   27,   30,   31,   27,   30,
+       31,   27,   30,   31,   30,   31,    4,    5,   29,    6,
+
+        6,    6,    6,    6,   10,16393,   11,   10,   10,   10,
+       10,    3,    3,    3,    3,    3,    4,    3,    5,    3,
+        3,   29,    3,    3,    3,    3,   17,    3,    3,    3,
+        3,    3,    3,   18,    4,   18,    5,   18,   18,   18,
+       29,   18,   18,   18,   18,   18,   22,    4,   22,    5,
+       22,   22,   22,   29,   22,   26,   22,   22,   22,   22,
+       22,   27,    4,   27,    5,   27,   27,   27,   29,   27,
+       27,   27,   27,   27,    6,    6,    6,    6,   10,   10,
+       10,   10,    3,    3,   29,    3,    3,    3,    3,    3,
+        3,    3,   18,   18,   18,   18,   22,   22,   29,   22,
+
+       22,   22,   22,   22,   27,   27,   27,   27,    8,    6,
+        6,    6,    6,   20,   10,   10,   10,   10,    3,    3,
+        3,    3,    3,   18,   18,   18,   18,   22,   22,   22,
+       22,   27,   27,   27,   27,    6,    6,    6,    6, 8201,
+       10,   10,   10,   10,    3,    3,    3,    3,   18,   18,
+       18,   18,   22,   22,   22,   22,   27,   27,   27,   27,
+        6,    6,    6,    6,   10,   10,   10,   10,    3,    3,
+        3,    3,   18,   18,   18,   18,   22,   22,   22,   22,
+       27,   27,   27,   27,    6,    6,    6,   10,   10,   10,
+        3,    3,    3,   18,   18,   18,   22,   22,   22,   27,
+
+       27,   27,    6,    6,   10,16393,   10,    3,    3,    3,
+       18,   18,   18,   22,   22,   22,   27,   27,   27,    7,
+        6,    6,    7,   10,   10,    3,    3,    7,    3,    7,
+        3,    7,    3,    7,    3,   18,    7,   18,   18,   18,
+       18,   18,   18,   22,    7,   22,   22,   27,    7,   27,
+       27,   27,   27,   27,   27,    6,    6,   10,   10,    3,
+        3,    7,    3,   18,   18,   18,   18,   18,   18,   18,
+       22,    7,   22,   22,   27,   27,   27,   27,   27,   27,
+       27,    2,    2,    6,    6,    2,    2,   10,   10,    2,
+        3,    3,    2,   18,   18,   18,   18,   18,    2,   22,
+
+       22,    2,   27,   27,   27,   27,   27,    6,   10,    3,
+       18,   18,   22,   27,   27,    6,   10,    3,   18,   22,
+       27,    6,   10,    3,   18,   22,   27,    6,   10,    3,
+       18,   22,   27,    6,   10,    3,   18,   22,   27,    1,
+        1,    6,    1,    1,   10,    1,    3,    1,   18,    1,
+       22,    1,   27
+    } ;
+
+static yyconst flex_int16_t yy_accept[683] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    3,    5,    5,    5,    6,    7,    9,
+       11,   11,   11,   12,   13,   13,   13,   14,   16,   19,
+       21,   23,   25,   27,   29,   31,   34,   36,   39,   42,
+       45,   47,   49,   51,   53,   55,   57,   59,   61,   63,
+       65,   67,   70,   72,   75,   78,   81,   84,   86,   88,
+       90,   93,   97,  100,  103,  106,  109,  111,  114,  117,
+      120,  123,  126,  129,  132,  135,  137,  139,  141,  144,
+      148,  151,  154,  157,  160,  163,  166,  169,  172,  176,
+      179,  182,  185,  188,  191,  194,  197,  200,  204,  207,
+
+      210,  213,  216,  218,  221,  224,  227,  230,  233,  235,
+      237,  239,  242,  246,  249,  252,  255,  258,  261,  264,
+      267,  270,  274,  277,  280,  283,  286,  289,  292,  295,
+      297,  298,  299,  299,  300,  300,  300,  300,  300,  300,
+      301,  301,  301,  301,  301,  301,  301,  301,  302,  303,
+      304,  305,  305,  305,  305,  305,  305,  305,  305,  305,
+      305,  305,  305,  305,  305,  305,  305,  305,  305,  306,
+      307,  307,  308,  308,  308,  308,  308,  308,  308,  309,
+      310,  311,  312,  312,  312,  313,  313,  314,  315,  315,
+      316,  316,  316,  316,  318,  320,  321,  323,  324,  324,
+
+      325,  326,  326,  327,  327,  327,  327,  328,  329,  329,
+      329,  329,  330,  331,  332,  333,  334,  334,  334,  335,
+      337,  339,  340,  342,  343,  344,  345,  346,  347,  348,
+      348,  348,  348,  348,  350,  352,  353,  355,  356,  356,
+      356,  356,  356,  357,  358,  358,  358,  358,  359,  360,
+      361,  362,  362,  362,  363,  365,  367,  368,  370,  371,
+      372,  373,  374,  375,  375,  375,  375,  375,  375,  375,
+      375,  375,  375,  375,  375,  376,  377,  378,  379,  379,
+      379,  379,  379,  379,  379,  379,  379,  379,  379,  379,
+      379,  380,  381,  382,  383,  383,  384,  386,  387,  387,
+
+      387,  387,  388,  388,  388,  388,  388,  389,  390,  391,
+      392,  393,  393,  394,  395,  396,  397,  398,  400,  401,
+      401,  401,  401,  401,  401,  401,  401,  402,  403,  404,
+      405,  405,  406,  407,  408,  409,  409,  410,  410,  410,
+      410,  410,  410,  410,  410,  411,  412,  413,  414,  415,
+      415,  415,  415,  415,  415,  415,  415,  415,  415,  415,
+      415,  416,  417,  418,  419,  419,  419,  420,  420,  420,
+      421,  422,  423,  424,  425,  426,  427,  428,  428,  428,
+      428,  428,  429,  430,  431,  432,  433,  434,  435,  436,
+      436,  436,  436,  436,  436,  437,  438,  439,  440,  440,
+
+      440,  440,  440,  440,  441,  441,  441,  442,  443,  444,
+      445,  445,  446,  447,  448,  449,  450,  451,  452,  453,
+      453,  454,  455,  456,  457,  458,  459,  460,  461,  461,
+      461,  461,  461,  462,  463,  464,  465,  465,  465,  465,
+      465,  465,  466,  467,  468,  469,  470,  471,  472,  473,
+      474,  475,  476,  477,  478,  479,  480,  481,  482,  483,
+      484,  485,  485,  485,  485,  486,  487,  488,  488,  488,
+      488,  489,  490,  491,  492,  493,  494,  495,  496,  497,
+      498,  499,  500,  501,  502,  503,  503,  503,  503,  504,
+      505,  505,  505,  505,  506,  507,  508,  509,  510,  511,
+
+      512,  513,  514,  515,  516,  517,  518,  519,  520,  520,
+      521,  521,  521,  521,  521,  521,  522,  523,  523,  524,
+      524,  525,  526,  527,  529,  529,  531,  533,  535,  535,
+      535,  535,  536,  537,  539,  540,  541,  542,  543,  544,
+      545,  547,  547,  547,  547,  547,  548,  549,  551,  552,
+      553,  554,  555,  556,  556,  556,  556,  556,  556,  556,
+      556,  557,  558,  558,  558,  559,  560,  561,  563,  563,
+      563,  563,  563,  563,  564,  565,  566,  567,  568,  569,
+      570,  571,  572,  574,  574,  574,  574,  574,  574,  575,
+      576,  577,  578,  579,  580,  581,  582,  583,  583,  583,
+
+      583,  583,  585,  586,  587,  587,  589,  590,  592,  592,
+      592,  592,  593,  595,  596,  597,  598,  599,  601,  601,
+      601,  601,  602,  604,  605,  606,  607,  608,  608,  608,
+      609,  609,  610,  610,  611,  612,  613,  613,  614,  615,
+      616,  616,  617,  617,  618,  619,  620,  621,  622,  622,
+      623,  623,  624,  625,  626,  627,  628,  628,  629,  629,
+      630,  631,  632,  633,  634,  634,  635,  635,  636,  637,
+      638,  639,  640,  641,  643,  644,  646,  648,  650,  652,
+      654,  654
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    4,    5,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    6,    7,    8,    1,    1,    9,    1,    1,    1,
+        1,    1,    1,    1,   10,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,   11,   12,
+       13,   14,    1,   15,    1,    1,   16,   17,   18,    1,
+        1,    1,   19,    1,    1,   20,   21,   22,   23,    1,
+        1,    1,   24,    1,    1,    1,    1,   25,    1,    1,
+        1,    1,    1,    1,   26,    1,   27,   28,   29,    1,
+
+       30,   31,    1,   32,   33,    1,    1,   34,   35,   36,
+       37,    1,    1,   38,   39,   40,   41,    1,    1,   42,
+       43,    1,   44,    1,   45,    1,    1,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   46,   46,   46,
+       46,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   47,   47,   47,   47,   47,   47,   47,
+       47,   47,   47,   48,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48,   48,   48,   49,
+       49,   49,   49,   49,   49,   49,   49,   50,   50,   50,
+       50,   50,   50,   50,   50
+    } ;
+
+static yyconst flex_int32_t yy_meta[51] =
+    {   0,
+        1,    2,    3,    2,    3,    2,    4,    5,    1,    1,
+        6,    4,    1,    4,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    7,    7,    8,    1,    1,    1,    8
+    } ;
+
+static yyconst flex_int16_t yy_base[716] =
+    {   0,
+        0,   20,   40,   89,  138,  158,  178,  227,  276,  325,
+      374,  394,  415,    0,  464,  508,  552,  572,  592,  641,
+      690,  734,  778,  798,  818,    0, 2137, 2292,    6, 2292,
+     2133,    6, 2102,    0, 2090,   19,  838,   23,   99,   64,
+     2084, 2083, 2079,   27,  885,  933,  981,   84, 2078, 2077,
+     2076, 1029, 1076, 2292, 1124,   20,   28, 2075, 1988, 1987,
+     1165, 1213,   75,  116, 1260, 2024,   15,  198,  199, 2016,
+      204,  122,  352,  128, 2292, 1984, 1983, 1982, 2292,   76,
+     2292, 2024,   10, 1996,   86, 1984, 2292,    0,  147,    0,
+     2021,   11, 2292, 1993,   97, 1981,  124,  205,  168,  252,
+
+     1308, 2013,   36, 2292,  210,  339,  257, 2292, 1974, 1973,
+     1972, 2292,  164, 2292, 2014,  118, 1986,  158, 1974, 2292,
+        0,  258,    0, 2011,  188, 2292, 1983,  219, 1971,  260,
+      261, 2292,  151, 2292,  217, 1980, 1985, 1967, 1974,  263,
+        0, 1961, 1960, 1959, 1958, 1956, 1953,  304,  358,  474,
+      355, 1951, 1941,  273,  473,    0, 1938, 1937, 1936, 1935,
+     1934, 1933,  284,  325,  458,  329, 1932, 1931, 1946,  485,
+     1356, 2292, 1929, 1928, 1927, 1926, 1925, 1924,    4,  220,
+      319,   25, 1923, 1922,  314,  222,  476,  493, 1952,  528,
+     1920, 1919, 1918,    0,  315, 1403,  406,    0,  489, 1949,
+
+     1948,  503, 1947,  363,  498,  499, 1952,  544, 1913, 1912,
+     1911,  600,  559,  545,  579,  580, 1910, 1908,    0,  560,
+        0,  357,    0,  602, 1921, 1926, 1907, 1903,  578,  425,
+     1890, 1889, 1888,  626,  607, 1451,  620,    0,  654,  521,
+      614,  617, 1925,  667, 1886, 1885, 1884,  674,  699,  670,
+      711, 1883, 1882,    0,  676,    0,  722,    0,  723, 1896,
+     1901, 1883, 1890,  623,  759, 1877, 1876, 1875, 1887, 1900,
+     1885, 1877, 1870, 1869,  720,  724,  741,  807, 1868,  760,
+     1867, 1866,  487,  522,  778,  593, 1865,  744, 1864, 1863,
+      164,  634,  213,  127, 1862,    0,  808,    0,  729,  824,
+
+      825, 1892,  828,  829, 1859, 1856,  855,  856,  861,  862,
+      875, 1854, 1857, 1868, 1853, 1845,    0,  863,    0,  848,
+      873,  879,  895,  898, 1838, 1837,  874,  899,  905,  911,
+     1836, 1848, 1861, 1846, 1838,  925, 2292, 1831, 1830, 1839,
+     1852, 1838, 1833, 1818,  919,  948,  960,  953,  900, 1817,
+      943,  726,  887,  958,  957, 1008, 1816, 1814, 1809, 1806,
+      256,  226,  265,  308,  967,  972, 1828, 1012, 1795, 1018,
+     1021, 1030, 1037, 1801, 1820, 1806, 1800, 1039, 1043, 1046,
+     1783, 1017, 1046, 1051, 1054, 1785, 1804, 1790, 1785, 1770,
+     1782, 1791, 1775, 1782, 1058, 1063, 1095, 1100, 1038, 1027,
+
+      647, 1090, 1111, 2292, 1760, 1759,  360,  362,  669,  747,
+     1070, 1132, 1135, 1149, 1155, 1769, 1770, 1755, 1762, 1147,
+     1154, 1147, 1151, 1160, 1757, 1766, 1751, 1757, 1742, 1748,
+     1733, 1735, 1157, 1202, 1182, 1207, 1202, 1146, 1207,  501,
+     1717,  578,   77,  777,  191, 1232, 1242, 1276, 1282, 1718,
+     1724, 1706, 1700, 1243, 1276, 1284, 1290, 1684, 1698, 1682,
+     1676, 1661, 1179, 1665, 1248, 1338, 1318, 1285, 1344, 1249,
+      538, 1367,  561, 1374, 1324, 1373, 1656, 1386, 1661, 1382,
+     1392, 1372, 1645, 1420, 1649, 1635, 1459, 1633, 1386, 1428,
+     1203, 1507,  779,  757, 1555,  719, 1465, 1603, 1440, 1633,
+
+     1651, 1598, 1436, 1700, 1477, 1593, 1748, 1585, 1586, 1525,
+     1796, 1554, 1549, 1541, 1556, 1494, 1523, 1217, 1542, 1461,
+      894,  314, 1468, 1844,  945, 1555, 1554, 1551, 1514, 1506,
+     1501, 1486, 1501, 1892, 1527, 1482, 1477, 1468, 1484, 1531,
+     1941, 1253, 1443, 1435, 1434, 1536, 1422, 1989, 1543, 1411,
+     1392, 1390, 1406, 1389, 1381, 1379, 1364, 1363, 1356, 1365,
+     1549, 1577, 1354, 1311,   26,  919, 1625,    0, 1337, 1336,
+     1314, 1305, 1303, 1515, 1304, 1290, 1288, 1275, 1241, 1220,
+     1235, 1572,    0, 1212, 1199, 1195, 1164, 1136, 1590, 1138,
+     1121, 1116, 1100, 1099, 1094, 1107, 2292, 1081, 1075, 1072,
+
+     1071, 1585, 1626,  818, 1475, 1067,  883, 1638, 1050, 1036,
+     1028, 1639,    0, 1023, 1001,  975,  973, 1619,  957,  952,
+      938, 1637,    0,  928,  910,  904,  866,  845,  838, 1678,
+     1259,  910,  791, 1675,  732,  663,  635, 1681,  620,  616,
+      606, 1687, 1631, 1162, 1689,  596, 1728,  515,  490, 1674,
+     1701,  941, 1737,  461, 1724,  376,  350, 1731, 1504,  679,
+     1779,  255, 1775,  217,  135, 1778, 1425, 1022, 1826,  111,
+     1822,   92, 2292, 1791, 1464,    9, 1762,    0, 1825,    0,
+     2292, 2039, 2047, 2055, 2063, 2071, 2079, 2087, 2095, 2103,
+     2111, 2119, 2126, 2133, 2140, 2144, 2152, 2159, 2167, 2175,
+
+     2179, 2187, 2194, 2202, 2210, 2217, 2225, 2233, 2240, 2247,
+     2254, 2262, 2269, 2277, 2284
+    } ;
+
+static yyconst flex_int16_t yy_def[716] =
+    {   0,
+      682,  682,  683,  683,  682,  682,  684,  684,  685,  685,
+      682,  682,  681,   13,  686,  686,  687,  687,  688,  688,
+      689,  689,  690,  690,  682,   25,  681,  681,  681,  681,
+      681,  691,  681,  681,  681,  692,  692,  692,  692,  692,
+      681,  681,  681,  693,  693,  693,  693,   47,  681,  681,
+      681,  694,  694,  681,  694,   55,   55,  681,  681,  681,
+      695,  695,   62,   62,  696,  681,  697,   62,   62,  681,
+       62,   62,   62,   62,  681,  681,  681,  681,  681,  681,
+      681,  681,  691,  681,  681,  681,  681,  698,  698,  698,
+      698,  699,  681,  698,  698,  698,  700,  700,  700,  700,
+
+      701,  681,  702,  681,  700,  700,  700,  681,  681,  681,
+      681,  681,  681,  681,  681,  691,  681,  681,  681,  681,
+      703,  703,  703,  703,  704,  681,  703,  703,  703,  705,
+      681,  681,  691,  681,  691,  681,  681,  681,  681,  692,
+       37,  681,  681,  681,  681,  681,  681,  692,  692,  692,
+      692,  681,  681,   47,  681,   45,  681,  681,  681,  681,
+      681,  681,   47,   47,   47,   47,  681,  681,   55,  681,
+      694,  681,  681,  681,  681,  681,  681,  681,   55,   55,
+       55,   55,  681,  681,   62,  697,   62,   62,  681,   62,
+      681,  681,  681,   62,   62,  696,   62,  196,  706,  196,
+
+      196,  691,  196,  691,  691,  691,  681,   62,  681,  681,
+      681,   62,   62,   62,   62,   62,  681,  681,  698,  698,
+      698,  699,  698,  699,  698,  698,  698,  698,  700,  702,
+      681,  681,  681,  700,  700,  701,  700,  236,  707,  691,
+      691,  691,  681,  700,  681,  681,  681,  700,  700,  700,
+      700,  681,  681,  703,  703,  703,  704,  703,  704,  703,
+      703,  703,  703,  705,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  692,  692,  692,  692,  681,  681,
+      681,  681,   47,   47,   47,   47,  681,  708,  681,  681,
+       55,   55,   55,   55,  681,  196,   62,  196,  691,  691,
+
+      691,  196,  691,  691,  681,  681,   62,   62,   62,   62,
+       62,  681,  698,  698,  698,  698,  236,  700,  236,  691,
+      691,  691,  691,  691,  681,  681,  700,  700,  700,  700,
+      681,  703,  703,  703,  703,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  692,  692,  692,  692,  681,  681,
+       47,   47,   47,   47,  708,  681,  681,  681,  681,  681,
+       55,   55,   55,   55,  691,  691,  196,  691,  681,   62,
+       62,   62,   62,  698,  698,  698,  698,  691,  691,  691,
+      681,  700,  700,  700,  700,  703,  703,  703,  703,  681,
+      681,  681,  681,  681,  692,  692,  692,  692,   47,   47,
+
+       47,   47,  681,  681,  681,  681,   55,   55,   55,   55,
+      691,   62,   62,   62,   62,  698,  698,  698,  698,  691,
+      700,  700,  700,  700,  703,  703,  703,  703,  681,  681,
+      681,  681,  692,  692,  692,  692,   47,   47,   47,   47,
+      681,   55,   55,   55,   55,   62,   62,   62,   62,  698,
+      698,  698,  698,  700,  700,  700,  700,  703,  703,  703,
+      703,  681,  681,  681,  692,  692,  692,   47,   47,   47,
+       55,   55,   55,   62,   62,   62,  698,  698,  698,  700,
+      700,  700,  703,  703,  703,  681,  709,  681,  692,  692,
+       47,  709,   47,   55,  709,   55,   62,  710,   62,  698,
+
+      711,  698,  700,  712,  700,  703,  713,  703,  681,  495,
+      709,  681,  681,  681,  681,  692,  692,   47,  495,   47,
+       55,   55,   62,  710,  714,  524,  524,  524,  681,  681,
+      681,   62,  698,  711,  711,  698,  698,  698,  698,  700,
+      712,  715,  681,  681,  681,  700,  703,  713,  713,  703,
+      703,  703,  703,  681,  681,  681,  681,  681,  681,  681,
+      692,  692,   47,   47,   55,   55,   62,  524,  681,  681,
+      681,  681,  681,   62,  698,  698,  698,  698,  698,  698,
+      698,  700,  541,  681,  681,  681,  681,  681,  700,  703,
+      703,  703,  703,  703,  703,  703,  681,  681,  681,  681,
+
+      681,  692,  692,   47,   47,   55,   55,   62,  681,  681,
+      681,   62,  698,  698,  698,  698,  698,  700,  681,  681,
+      681,  700,  703,  703,  703,  703,  703,  681,  681,  692,
+       47,   55,  681,   62,  698,  698,  681,  700,  703,  703,
+      681,  692,   47,   55,   62,  698,  700,  703,  681,  692,
+       47,   55,   62,  698,  700,  703,  681,  692,   47,   55,
+       62,  698,  700,  703,  681,  692,   47,   55,   62,  698,
+      700,  703,  681,  692,   47,   55,   62,  698,  700,  703,
+        0,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681
+    } ;
+
+static yyconst flex_int16_t yy_nxt[2343] =
+    {   0,
+      681,   29,   30,   29,   31,   29,   32,  131,  134,  131,
+      135,  131,  134,  223,  135,  224,   33,  137,  133,   34,
+       35,   29,   30,   29,   31,   29,   32,  141,  155,  138,
+      155,  141,  155,  169,  291,  156,   33,  180,  169,   34,
+       35,   29,   30,   29,   31,   29,   32,   28,   37,  181,
+       28,   28,  148,   28,  169,  169,   38,  169,  294,   39,
+       40,  209,  210,  211,  606,  142,  143,  144,  182,  142,
+      143,  144,  141,  157,  158,  159,  185,  131,  185,  131,
+      185,  131,  245,  246,  247,   28,   41,   42,   43,   28,
+       29,   30,   29,   31,   29,   32,   28,   37,  472,   28,
+
+       28,  154,   28,  137,  151,   38,  169,  141,   39,   40,
+      142,  143,  144,  154,  226,  138,  149,  185,  195,  185,
+      134,  185,  135,  185,  166,  185,  227,  185,  150,  185,
+      680,  185,  230,  185,   28,   41,   42,   43,   28,   29,
+       30,   29,   31,   29,   32,  142,  143,  144,  220,  678,
+      220,  213,  220,  134,   33,  135,  169,   34,   35,   29,
+       30,   29,   31,   29,   32,  131,  364,  131,  216,  131,
+      231,  232,  233,  673,   33,  137,  230,   34,   35,   29,
+       30,   29,   31,   29,   32,   28,   45,  138,   28,   28,
+      258,   28,  259,  169,   46,  133,  361,   47,   48,  185,
+
+      185,  185,  185,  185,  185,  185,  234,  185,  234,  185,
+      234,  212,  212,  230,  231,  232,  233,  212,  230,  134,
+      169,  135,  473,   28,   49,   50,   51,   28,   29,   30,
+       29,   31,   29,   32,   28,   45,  261,   28,   28,  248,
+       28,  408,  169,   46,  292,  363,   47,   48,  262,  169,
+      672,  231,  232,  233,  235,  169,  231,  232,  233,  255,
+      230,  255,  131,  255,  131,  230,  131,  265,  209,  210,
+      211,  141,   28,   49,   50,   51,   28,   29,   30,   29,
+       31,   29,   32,   28,   53,  169,   28,   54,  670,   28,
+      154,  407,   55,  409,  169,   56,   57,  251,  231,  232,
+
+      233,  154,  154,  231,  232,  233,  266,  267,  268,  142,
+      143,  144,  141,  154,  283,  185,  185,  185,  185,  185,
+      185,   28,   58,   59,   60,   28,   29,   30,   29,   31,
+       29,   32,   28,   53,  275,   28,   54,  169,   28,  566,
+      410,   55,  154,  169,   56,   57,  154,  230,  169,  284,
+      142,  143,  144,  185,  154,  185,  249,  185,  154,  223,
+      293,  224,  286,  141,  133,  134,  141,  135,  250,  214,
+       28,   58,   59,   60,   28,   29,   30,   29,   31,   29,
+       32,  215,  276,  665,  443,  231,  232,  233,  278,  169,
+       33,  169,  442,   34,   35,   29,   30,   29,   31,   29,
+
+       32,  142,  143,  144,  142,  143,  144,  185,  196,  185,
+       33,  185,  664,   34,   35,   61,   62,   63,   62,   64,
+       62,   65,   66,   67,   68,   28,   61,   69,   70,   71,
+       61,   72,   61,   61,   73,   74,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   75,   28,
+       28,   76,   77,   78,   28,   80,   81,   80,   82,   80,
+       83,  245,  246,  247,  155,  154,  155,  185,  155,  185,
+       84,  185,  141,   85,   86,  280,  170,  154,  170,  212,
+      170,  297,  288,  298,  185,  172,  185,  662,  185,  285,
+
+      134,  134,  135,  135,  154,  134,  212,  135,   87,   80,
+       81,   80,   82,   80,   83,  277,  154,  196,  154,  351,
+      142,  143,  144,  134,   84,  135,  657,   85,   86,  185,
+      154,  185,  470,  185,  133,  299,  300,  301,  133,  154,
+      352,  212,  656,  303,  304,  185,  185,  185,  185,  185,
+      185,  154,   87,   89,   90,   89,   91,   89,   92,   93,
+      185,  220,  185,  220,  185,  220,  236,  169,   94,  309,
+      494,   95,   96,   89,   90,   89,   91,   89,   92,   93,
+      185,  185,  185,  185,  185,  185,  230,  496,   94,  308,
+      169,   95,   96,   98,   99,   98,  100,   98,  101,  102,
+
+      103,  185,  104,  185,  223,  185,  224,  169,  105,  133,
+      154,  106,  107,  311,  307,  230,  134,  471,  135,  134,
+      310,  135,  154,  654,  231,  232,  233,  234,  230,  234,
+      265,  234,  354,  649,  230,  108,   28,   28,  109,  110,
+      111,   28,   98,   99,   98,  100,   98,  101,  102,  103,
+      648,  104,  362,  231,  232,  233,  318,  105,  319,  323,
+      106,  107,  324,  169,  154,  548,  231,  232,  233,  266,
+      267,  268,  231,  232,  233,  230,  154,  255,  230,  255,
+      583,  255,  230,  439,  108,   28,   28,  109,  110,  111,
+       28,  113,  114,  113,  115,  113,  116,  646,  169,  133,
+
+      320,  321,  322,  133,  327,  444,  117,  230,  169,  118,
+      119,  329,  668,  231,  232,  233,  231,  232,  233,  230,
+      231,  232,  233,  328,  258,  258,  259,  259,  141,  133,
+      133,  134,  141,  135,  120,  113,  114,  113,  115,  113,
+      116,  400,  346,  154,  330,  231,  232,  233,  169,  141,
+      117,  356,  345,  118,  119,  154,  522,  231,  232,  233,
+      336,  349,  336,  349,  336,  349,  142,  143,  144,  337,
+      142,  143,  144,  347,  296,  445,  169,  534,  120,  122,
+      123,  122,  124,  122,  125,  126,  169,  142,  143,  144,
+      357,  358,  359,  521,  127,  154,  154,  128,  129,  122,
+
+      123,  122,  124,  122,  125,  126,  169,  154,  154,  185,
+      353,  185,  472,  185,  127,  141,  520,  128,  129,   29,
+       30,   29,   31,   29,   32,  130,  134,  134,  135,  135,
+      134,  134,  135,  135,   33,  154,  568,   34,   35,  140,
+      140,  140,  140,  140,  140,  140,  348,  154,  140,  140,
+      134,  140,  135,  142,  143,  144,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  212,  365,
+      366,  230,  641,  196,  368,  134,  185,  135,  185,  371,
+      185,  134,  230,  135,  145,  146,  147,  154,  370,  154,
+      510,  154,  154,  317,  372,  154,  154,  134,  154,  135,
+
+      134,  349,  135,  349,  154,  349,  382,  230,  640,  231,
+      232,  233,  169,  230,  373,  401,  154,  383,  378,  230,
+      231,  232,  233,  169,  379,  632,  336,  141,  336,  565,
+      336,  160,  161,  162,  155,  337,  155,  384,  155,  169,
+      236,  156,  607,  380,  644,  231,  232,  233,  169,  548,
+      385,  231,  232,  233,  395,  639,  141,  231,  232,  233,
+      154,  141,  163,  396,  356,  142,  143,  144,  141,  134,
+      169,  135,  154,  548,  134,  154,  135,  660,  399,  157,
+      158,  159,  155,  541,  155,  398,  155,  154,  397,  156,
+      402,  569,  570,  571,  142,  143,  144,  637,  164,  142,
+
+      143,  144,  583,  357,  358,  359,  142,  143,  144,  403,
+      165,  403,  296,  403,  134,  636,  135,  411,  404,  185,
+      534,  185,  185,  185,  185,  230,  185,  157,  158,  159,
+      170,  185,  170,  185,  170,  185,  413,  171,  185,  172,
+      185,  134,  185,  135,  154,  134,  635,  135,  134,  438,
+      135,  169,  421,  412,  230,  154,  154,  196,  414,  230,
+      676,  422,  230,  231,  232,  233,  141,  154,  534,  415,
+      437,  141,  134,  524,  135,  173,  174,  175,  169,  423,
+      169,  633,  169,  169,  317,  434,  424,  169,  420,  169,
+      433,  236,  231,  232,  233,  568,  169,  231,  232,  233,
+
+      231,  232,  233,  141,  142,  143,  144,  154,  141,  142,
+      143,  144,  403,  629,  403,  296,  403,  510,  440,  154,
+      628,  404,  176,  177,  178,  170,  510,  170,  436,  170,
+      627,  435,  171,  185,  172,  185,  185,  185,  185,  626,
+      185,  142,  143,  144,  548,  625,  142,  143,  144,  134,
+      185,  135,  185,  179,  185,  230,  185,  447,  185,  230,
+      185,  624,  230,  154,  446,  141,  548,  469,  230,  455,
+      173,  174,  175,  186,  187,  154,  623,  188,  189,  190,
+      487,  621,  487,  449,  487,  448,  454,  456,  457,  652,
+      141,  169,  317,  231,  232,  233,  465,  231,  232,  233,
+
+      231,  232,  233,  142,  143,  144,  231,  232,  233,  541,
+      141,  191,  192,  193,  194,  141,  194,  466,  194,  154,
+      154,  186,  187,  466,  154,  188,  189,  190,  142,  143,
+      144,  154,  154,  185,  154,  185,  154,  185,  467,  518,
+      620,  468,  469,  185,  619,  185,  154,  185,  142,  143,
+      144,  230,  563,  142,  143,  144,  141,  583,  617,  191,
+      192,  193,  197,  475,  198,  616,  154,  133,  199,  200,
+      133,  474,  201,  202,  203,  493,  154,  185,  154,  185,
+      489,  185,  480,  185,  230,  185,  534,  185,  154,  231,
+      232,  233,  230,  643,  142,  143,  144,  481,  230,  584,
+
+      585,  586,  154,  133,  133,  133,  204,  205,  206,  133,
+      237,  475,  238,  476,  154,  133,  239,  491,  133,  481,
+      615,  482,  231,  232,  233,  498,  141,  498,  154,  498,
+      231,  232,  233,  614,  605,  534,  231,  232,  233,  487,
+      154,  487,  613,  487,  490,  492,  141,  492,  611,  492,
+      524,  133,  133,  133,  240,  241,  242,  133,  169,  610,
+      169,  154,  169,  169,  142,  143,  144,  169,  495,  169,
+      495,  154,  495,  154,  185,  185,  185,  185,  185,  185,
+      230,  609,  568,  154,  142,  143,  144,  501,  601,  501,
+      230,  501,  604,  504,  141,  504,  169,  504,  505,  499,
+
+      230,  600,  176,  177,  178,  197,  497,  198,  510,  599,
+      133,  199,  200,  133,  503,  201,  202,  203,  231,  232,
+      233,  507,  516,  507,  598,  507,  510,  597,  231,  232,
+      233,  596,  142,  143,  144,  595,  141,  594,  231,  232,
+      233,  185,  154,  185,  230,  185,  133,  133,  133,  204,
+      205,  206,  133,  237,  154,  238,  548,  590,  133,  239,
+      487,  133,  487,  675,  487,  517,  185,  511,  185,  185,
+      185,  185,  540,  185,  142,  143,  144,  532,  154,  588,
+      587,  154,  231,  232,  233,  230,  564,  185,  541,  185,
+      154,  185,  154,  154,  133,  133,  133,  240,  241,  242,
+
+      133,  523,  141,  567,  154,  512,  513,  514,  492,  581,
+      492,  574,  492,  580,  546,  511,  185,  631,  185,  519,
+      185,  154,  579,  231,  232,  233,  681,  534,  681,  561,
+      681,  141,  681,  154,  510,  681,  575,  667,  612,  230,
+      142,  143,  144,  349,  230,  349,  573,  349,  562,  681,
+      510,  572,  681,  512,  513,  514,  495,  141,  495,  524,
+      495,  589,  288,  511,  212,  172,  582,  212,  212,  142,
+      143,  144,  219,  576,  577,  578,  219,  231,  232,  233,
+      230,  560,  231,  232,  233,  141,  559,  602,  254,  591,
+      592,  593,  254,  141,  558,  142,  143,  144,  230,  510,
+
+      603,  512,  513,  514,  498,  185,  498,  185,  498,  185,
+      618,  525,  526,  622,  185,  527,  189,  528,  231,  232,
+      233,  554,  553,  142,  143,  144,  185,  230,  185,  547,
+      185,  142,  143,  144,  141,  539,  231,  232,  233,  185,
+      185,  185,  185,  185,  185,  230,  510,  510,  154,  529,
+      530,  531,  501,  219,  501,  219,  501,  219,  651,  535,
+      154,  219,  219,  608,  219,  231,  232,  233,  630,  533,
+      515,  509,  142,  143,  144,  508,  185,  506,  185,  638,
+      185,  634,  141,  231,  232,  233,  141,  502,  500,  230,
+      185,  488,  185,  486,  185,  141,  219,  536,  537,  538,
+
+      219,  504,  229,  504,  229,  504,  229,  485,  542,  645,
+      658,  229,  642,  229,  650,  647,  653,  484,  154,  484,
+      142,  143,  144,  483,  142,  143,  144,  231,  232,  233,
+      154,  479,  230,  142,  143,  144,  230,  659,  185,  141,
+      185,  478,  185,  510,  510,  478,  543,  544,  545,  507,
+      254,  507,  254,  507,  254,  655,  549,  477,  254,  254,
+      663,  254,  355,  185,  666,  185,  464,  185,  463,  463,
+      231,  232,  233,  661,  231,  232,  233,  142,  143,  144,
+      185,  462,  185,  230,  185,  461,  141,  460,  459,  458,
+      453,  452,  451,  254,  550,  551,  552,  254,  510,  141,
+
+      510,  450,  510,  510,  441,  355,  510,  510,  671,  510,
+      432,  431,  669,  430,  429,  264,  674,  428,  427,  426,
+      425,  231,  232,  233,  142,  143,  144,  185,  244,  185,
+      230,  185,  419,  230,  418,  417,  416,  142,  143,  144,
+      208,  302,  555,  556,  557,  185,  185,  185,  185,  185,
+      185,  169,  525,  526,  406,  185,  527,  189,  528,  405,
+      679,  355,  154,  140,  677,  394,  393,  392,  231,  232,
+      233,  231,  232,  233,  391,  390,  264,  389,  388,  387,
+      386,  229,  381,  244,  377,  376,  375,  510,  510,  374,
+      529,  530,  531,  219,  219,  219,  219,  219,  219,  185,
+
+      535,  369,  219,  219,  208,  219,  367,  169,  360,  169,
+      154,  350,  154,  140,  344,  140,  343,  342,  341,  340,
+      339,  338,  264,  335,  334,  333,  332,  331,  229,  326,
+      325,  244,  243,  253,  252,  229,  316,  219,  536,  537,
+      538,  219,  229,  229,  229,  229,  229,  229,  315,  542,
+      314,  313,  229,  312,  229,  185,  306,  305,  208,  207,
+      302,  302,  302,  218,  217,  185,  185,  295,  169,  290,
+      289,  169,  184,  183,  169,  169,  287,  154,  282,  281,
+      154,  168,  167,  154,  510,  510,  279,  543,  544,  545,
+      254,  254,  254,  254,  254,  254,  140,  549,  274,  254,
+
+      254,  273,  254,  140,  153,  152,  140,  272,  271,  270,
+      269,  263,  260,  256,  139,  136,  132,  253,  252,  229,
+      243,  228,  225,  221,  139,  136,  132,  218,  217,  185,
+      185,  207,  184,  183,  254,  550,  551,  552,  254,   28,
+       28,   28,   28,   28,   28,   28,   28,   36,   36,   36,
+       36,   36,   36,   36,   36,   44,   44,   44,   44,   44,
+       44,   44,   44,   52,   52,   52,   52,   52,   52,   52,
+       52,   79,   79,   79,   79,   79,   79,   79,   79,   88,
+       88,   88,   88,   88,   88,   88,   88,   97,   97,   97,
+       97,   97,   97,   97,   97,  112,  112,  112,  112,  112,
+
+      112,  112,  112,  121,  121,  121,  121,  121,  121,  121,
+      121,  133,  133,  133,  133,  133,  133,  133,  133,  140,
+      169,  168,  167,  154,  153,  140,  154,  154,  152,  140,
+      139,  136,  154,  169,  169,  132,  681,  681,  169,  169,
+      185,  185,  185,  185,  196,  196,  196,  196,  196,  196,
+      196,  196,  208,  208,  208,  208,  208,  208,  208,  219,
+      219,  219,  219,  681,  219,  219,  219,  222,  222,  222,
+      222,  222,  222,  222,  222,  229,  229,  229,  229,  236,
+      236,  236,  236,  236,  236,  236,  236,  244,  244,  244,
+      244,  244,  244,  244,  254,  254,  254,  254,  681,  254,
+
+      254,  254,  257,  257,  257,  257,  257,  257,  257,  257,
+      264,  264,  681,  264,  264,  264,  264,  296,  296,  296,
+      296,  296,  296,  296,  296,  317,  317,  317,  317,  317,
+      317,  317,  317,  355,  355,  681,  355,  355,  355,  355,
+      510,  510,  681,  681,  681,  681,  510,  524,  524,  524,
+      524,  681,  681,  524,  534,  534,  534,  534,  681,  534,
+      534,  534,  541,  541,  541,  541,  681,  681,  541,  548,
+      548,  548,  548,  681,  548,  548,  548,  568,  568,  568,
+      568,  568,  568,  568,  583,  583,  583,  583,  583,  583,
+      583,   27,  681,  681,  681,  681,  681,  681,  681,  681,
+
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681
+    } ;
+
+static yyconst flex_int16_t yy_chk[2343] =
+    {   0,
+        0,    1,    1,    1,    1,    1,    1,   29,   32,   29,
+       32,   29,   83,   92,   83,   92,    1,   34,   92,    1,
+        1,    2,    2,    2,    2,    2,    2,   36,   44,   34,
+       44,   38,   44,  179,  179,   44,    2,   56,  676,    2,
+        2,    3,    3,    3,    3,    3,    3,    3,    3,   56,
+        3,    3,   38,    3,  182,  565,    3,   57,  182,    3,
+        3,   67,   67,   67,  565,   36,   36,   36,   57,   38,
+       38,   38,   40,   44,   44,   44,   63,   80,   63,   80,
+       63,   80,  103,  103,  103,    3,    3,    3,    3,    3,
+        4,    4,    4,    4,    4,    4,    4,    4,  443,    4,
+
+        4,   48,    4,   85,   40,    4,  443,   39,    4,    4,
+       40,   40,   40,   48,   95,   85,   39,   64,   64,   64,
+      116,   64,  116,   72,   48,   72,   95,   72,   39,   74,
+      672,   74,   97,   74,    4,    4,    4,    4,    4,    5,
+        5,    5,    5,    5,    5,   39,   39,   39,   89,  670,
+       89,   72,   89,  133,    5,  133,  294,    5,    5,    6,
+        6,    6,    6,    6,    6,  113,  294,  113,   74,  113,
+       97,   97,   97,  665,    6,  118,   99,    6,    6,    7,
+        7,    7,    7,    7,    7,    7,    7,  118,    7,    7,
+      125,    7,  125,  291,    7,  125,  291,    7,    7,   68,
+
+       69,   68,   69,   68,   69,   71,   98,   71,   98,   71,
+       98,   68,   69,   98,   99,   99,   99,   71,  105,  135,
+      445,  135,  445,    7,    7,    7,    7,    7,    8,    8,
+        8,    8,    8,    8,    8,    8,  128,    8,    8,  105,
+        8,  362,  293,    8,  180,  293,    8,    8,  128,  180,
+      664,   98,   98,   98,  100,  362,  105,  105,  105,  122,
+      100,  122,  131,  122,  131,  107,  131,  130,  186,  186,
+      186,  140,    8,    8,    8,    8,    8,    9,    9,    9,
+        9,    9,    9,    9,    9,  361,    9,    9,  662,    9,
+      154,  361,    9,  363,  363,    9,    9,  107,  100,  100,
+
+      100,  163,  154,  107,  107,  107,  130,  130,  130,  140,
+      140,  140,  148,  163,  163,  185,  195,  185,  195,  185,
+      195,    9,    9,    9,    9,    9,   10,   10,   10,   10,
+       10,   10,   10,   10,  148,   10,   10,  364,   10,  522,
+      364,   10,  164,  522,   10,   10,  166,  106,  181,  164,
+      148,  148,  148,   73,  164,   73,  106,   73,  166,  222,
+      181,  222,  166,  151,  222,  204,  149,  204,  106,   73,
+       10,   10,   10,   10,   10,   11,   11,   11,   11,   11,
+       11,   73,  149,  657,  408,  106,  106,  106,  151,  407,
+       11,  408,  407,   11,   11,   12,   12,   12,   12,   12,
+
+       12,  151,  151,  151,  149,  149,  149,  197,  204,  197,
+       12,  197,  656,   12,   12,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   15,   15,   15,   15,   15,
+       15,  230,  230,  230,  155,  165,  155,  187,  155,  187,
+       15,  187,  150,   15,   15,  155,  170,  165,  170,  187,
+      170,  199,  170,  199,  188,  170,  188,  654,  188,  165,
+
+      205,  206,  205,  206,  283,  202,  188,  202,   15,   16,
+       16,   16,   16,   16,   16,  150,  283,  202,  440,  283,
+      150,  150,  150,  240,   16,  240,  649,   16,   16,  190,
+      440,  190,  440,  190,  199,  199,  199,  199,  199,  284,
+      284,  190,  648,  205,  206,  208,  214,  208,  214,  208,
+      214,  284,   16,   17,   17,   17,   17,   17,   17,   17,
+      213,  220,  213,  220,  213,  220,  240,  471,   17,  214,
+      471,   17,   17,   18,   18,   18,   18,   18,   18,   18,
+      215,  216,  215,  216,  215,  216,  229,  473,   18,  213,
+      473,   18,   18,   19,   19,   19,   19,   19,   19,   19,
+
+       19,  212,   19,  212,  224,  212,  224,  442,   19,  224,
+      286,   19,   19,  216,  212,  235,  241,  442,  241,  242,
+      215,  242,  286,  646,  229,  229,  229,  234,  237,  234,
+      264,  234,  286,  641,  234,   19,   19,   19,   19,   19,
+       19,   19,   20,   20,   20,   20,   20,   20,   20,   20,
+      640,   20,  292,  235,  235,  235,  239,   20,  239,  241,
+       20,   20,  242,  292,  401,  639,  237,  237,  237,  264,
+      264,  264,  234,  234,  234,  244,  401,  255,  250,  255,
+      637,  255,  248,  401,   20,   20,   20,   20,   20,   20,
+       20,   21,   21,   21,   21,   21,   21,  636,  409,  239,
+
+      239,  239,  239,  239,  248,  409,   21,  249,  660,   21,
+       21,  250,  660,  244,  244,  244,  250,  250,  250,  251,
+      248,  248,  248,  249,  257,  259,  257,  259,  275,  257,
+      259,  299,  276,  299,   21,   22,   22,   22,   22,   22,
+       22,  352,  276,  352,  251,  249,  249,  249,  496,  277,
+       22,  288,  275,   22,   22,  352,  496,  251,  251,  251,
+      265,  280,  265,  280,  265,  280,  275,  275,  275,  265,
+      276,  276,  276,  277,  299,  410,  410,  635,   22,   23,
+       23,   23,   23,   23,   23,   23,  494,  277,  277,  277,
+      288,  288,  288,  494,   23,  285,  493,   23,   23,   24,
+
+       24,   24,   24,   24,   24,   24,  444,  285,  493,  297,
+      285,  297,  444,  297,   24,  278,  493,   24,   24,   25,
+       25,   25,   25,   25,   25,   25,  300,  301,  300,  301,
+      303,  304,  303,  304,   25,  604,  633,   25,   25,   37,
+       37,   37,   37,   37,   37,   37,  278,  604,   37,   37,
+      320,   37,  320,  278,  278,  278,  307,  308,  307,  308,
+      307,  308,  309,  310,  309,  310,  309,  310,  307,  300,
+      301,  318,  629,  303,  304,  321,  311,  321,  311,  309,
+      311,  322,  327,  322,   37,   37,   37,   45,  308,   45,
+      628,   45,   45,  320,  310,   45,   45,  323,   45,  323,
+
+      324,  349,  324,  349,  353,  349,  327,  328,  627,  318,
+      318,  318,  607,  329,  311,  353,  353,  328,  321,  330,
+      327,  327,  327,  521,  322,  607,  336,  345,  336,  521,
+      336,   45,   45,   45,   46,  336,   46,  329,   46,  632,
+      323,   46,  566,  324,  632,  328,  328,  328,  566,  626,
+      330,  329,  329,  329,  345,  625,  346,  330,  330,  330,
+      351,  348,   46,  346,  355,  345,  345,  345,  347,  365,
+      652,  365,  351,  624,  366,  354,  366,  652,  351,   46,
+       46,   46,   47,  621,   47,  348,   47,  354,  347,   47,
+      354,  525,  525,  525,  346,  346,  346,  620,   47,  348,
+
+      348,  348,  619,  355,  355,  355,  347,  347,  347,  356,
+       47,  356,  365,  356,  368,  617,  368,  366,  356,  370,
+      616,  370,  371,  370,  371,  382,  371,   47,   47,   47,
+       52,  372,   52,  372,   52,  372,  371,   52,  373,   52,
+      373,  378,  373,  378,  400,  379,  615,  379,  380,  400,
+      380,  668,  382,  370,  383,  399,  400,  368,  372,  384,
+      668,  383,  385,  382,  382,  382,  395,  399,  614,  373,
+      399,  396,  411,  611,  411,   52,   52,   52,   53,  384,
+       53,  610,   53,   53,  378,  396,  385,   53,  379,   53,
+      395,  380,  383,  383,  383,  609,  606,  384,  384,  384,
+
+      385,  385,  385,  397,  395,  395,  395,  402,  398,  396,
+      396,  396,  403,  601,  403,  411,  403,  600,  402,  402,
+      599,  403,   53,   53,   53,   55,  598,   55,  398,   55,
+      596,  397,   55,  412,   55,  412,  413,  412,  413,  595,
+      413,  397,  397,  397,  594,  593,  398,  398,  398,  420,
+      414,  420,  414,   55,  414,  422,  415,  413,  415,  423,
+      415,  592,  421,  438,  412,  433,  591,  438,  424,  422,
+       55,   55,   55,   61,   61,  438,  590,   61,   61,   61,
+      463,  588,  463,  415,  463,  414,  421,  423,  424,  644,
+      435,  644,  420,  422,  422,  422,  433,  423,  423,  423,
+
+      421,  421,  421,  433,  433,  433,  424,  424,  424,  587,
+      434,   61,   61,   61,   62,  436,   62,  435,   62,  437,
+      491,   62,   62,  434,  439,   62,   62,   62,  435,  435,
+      435,  437,  491,  446,  518,  446,  439,  446,  436,  491,
+      586,  437,  439,  447,  585,  447,  518,  447,  434,  434,
+      434,  454,  518,  436,  436,  436,  465,  584,  581,   62,
+       62,   62,   65,  447,   65,  580,  470,   65,   65,   65,
+       65,  446,   65,   65,   65,  470,  631,  448,  470,  448,
+      465,  448,  454,  449,  455,  449,  579,  449,  631,  454,
+      454,  454,  456,  631,  465,  465,  465,  455,  457,  542,
+
+      542,  542,  468,   65,   65,   65,   65,   65,   65,   65,
+      101,  448,  101,  449,  468,  101,  101,  468,  101,  456,
+      578,  457,  455,  455,  455,  475,  467,  475,  564,  475,
+      456,  456,  456,  577,  564,  576,  457,  457,  457,  466,
+      564,  466,  575,  466,  467,  469,  466,  469,  573,  469,
+      572,  101,  101,  101,  101,  101,  101,  101,  171,  571,
+      171,  469,  171,  171,  467,  467,  467,  171,  472,  171,
+      472,  563,  472,  469,  476,  474,  476,  474,  476,  474,
+      482,  570,  569,  563,  466,  466,  466,  478,  560,  478,
+      480,  478,  563,  481,  489,  481,  472,  481,  482,  476,
+
+      481,  559,  171,  171,  171,  196,  474,  196,  558,  557,
+      196,  196,  196,  196,  480,  196,  196,  196,  482,  482,
+      482,  484,  489,  484,  556,  484,  555,  554,  480,  480,
+      480,  553,  489,  489,  489,  552,  490,  551,  481,  481,
+      481,  499,  667,  499,  503,  499,  196,  196,  196,  196,
+      196,  196,  196,  236,  667,  236,  550,  547,  236,  236,
+      487,  236,  487,  667,  487,  490,  497,  487,  497,  523,
+      497,  523,  503,  523,  490,  490,  490,  499,  520,  545,
+      544,  675,  503,  503,  503,  505,  520,  532,  543,  532,
+      520,  532,  605,  675,  236,  236,  236,  236,  236,  236,
+
+      236,  497,  516,  523,  605,  487,  487,  487,  492,  539,
+      492,  532,  492,  538,  505,  492,  574,  605,  574,  492,
+      574,  659,  537,  505,  505,  505,  510,  536,  510,  516,
+      510,  517,  510,  659,  535,  510,  533,  659,  574,  540,
+      516,  516,  516,  519,  546,  519,  531,  519,  517,  519,
+      549,  530,  519,  492,  492,  492,  495,  561,  495,  529,
+      495,  546,  495,  495,  528,  495,  540,  527,  526,  517,
+      517,  517,  535,  535,  535,  535,  535,  540,  540,  540,
+      582,  515,  546,  546,  546,  562,  514,  561,  549,  549,
+      549,  549,  549,  602,  513,  561,  561,  561,  589,  512,
+
+      562,  495,  495,  495,  498,  498,  498,  498,  498,  498,
+      582,  498,  498,  589,  498,  498,  498,  498,  582,  582,
+      582,  509,  508,  562,  562,  562,  567,  618,  567,  506,
+      567,  602,  602,  602,  603,  502,  589,  589,  589,  608,
+      612,  608,  612,  608,  612,  622,  498,  498,  643,  498,
+      498,  498,  501,  501,  501,  501,  501,  501,  643,  501,
+      643,  501,  501,  567,  501,  618,  618,  618,  603,  500,
+      488,  486,  603,  603,  603,  485,  634,  483,  634,  622,
+      634,  612,  650,  622,  622,  622,  630,  479,  477,  638,
+      645,  464,  645,  462,  645,  642,  501,  501,  501,  501,
+
+      501,  504,  504,  504,  504,  504,  504,  461,  504,  634,
+      650,  504,  630,  504,  642,  638,  645,  460,  651,  459,
+      650,  650,  650,  458,  630,  630,  630,  638,  638,  638,
+      651,  453,  655,  642,  642,  642,  647,  651,  653,  658,
+      653,  452,  653,  504,  504,  451,  504,  504,  504,  507,
+      507,  507,  507,  507,  507,  647,  507,  450,  507,  507,
+      655,  507,  441,  677,  658,  677,  432,  677,  431,  430,
+      655,  655,  655,  653,  647,  647,  647,  658,  658,  658,
+      661,  429,  661,  663,  661,  428,  666,  427,  426,  425,
+      419,  418,  417,  507,  507,  507,  507,  507,  511,  674,
+
+      511,  416,  511,  511,  406,  405,  511,  511,  663,  511,
+      394,  393,  661,  392,  391,  390,  666,  389,  388,  387,
+      386,  663,  663,  663,  666,  666,  666,  669,  381,  669,
+      671,  669,  377,  679,  376,  375,  374,  674,  674,  674,
+      369,  367,  511,  511,  511,  524,  524,  524,  524,  524,
+      524,  360,  524,  524,  359,  524,  524,  524,  524,  358,
+      671,  357,  350,  344,  669,  343,  342,  341,  671,  671,
+      671,  679,  679,  679,  340,  339,  338,  335,  334,  333,
+      332,  331,  326,  325,  316,  315,  314,  524,  524,  313,
+      524,  524,  524,  534,  534,  534,  534,  534,  534,  312,
+
+      534,  306,  534,  534,  305,  534,  302,  295,  290,  289,
+      287,  282,  281,  279,  274,  273,  272,  271,  270,  269,
+      268,  267,  266,  263,  262,  261,  260,  253,  252,  247,
+      246,  245,  243,  233,  232,  231,  228,  534,  534,  534,
+      534,  534,  541,  541,  541,  541,  541,  541,  227,  541,
+      226,  225,  541,  218,  541,  217,  211,  210,  209,  207,
+      203,  201,  200,  193,  192,  191,  189,  184,  183,  178,
+      177,  176,  175,  174,  173,  169,  168,  167,  162,  161,
+      160,  159,  158,  157,  541,  541,  153,  541,  541,  541,
+      548,  548,  548,  548,  548,  548,  152,  548,  147,  548,
+
+      548,  146,  548,  145,  144,  143,  142,  139,  138,  137,
+      136,  129,  127,  124,  119,  117,  115,  111,  110,  109,
+      102,   96,   94,   91,   86,   84,   82,   78,   77,   76,
+       70,   66,   60,   59,  548,  548,  548,  548,  548,  682,
+      682,  682,  682,  682,  682,  682,  682,  683,  683,  683,
+      683,  683,  683,  683,  683,  684,  684,  684,  684,  684,
+      684,  684,  684,  685,  685,  685,  685,  685,  685,  685,
+      685,  686,  686,  686,  686,  686,  686,  686,  686,  687,
+      687,  687,  687,  687,  687,  687,  687,  688,  688,  688,
+      688,  688,  688,  688,  688,  689,  689,  689,  689,  689,
+
+      689,  689,  689,  690,  690,  690,  690,  690,  690,  690,
+      690,  691,  691,  691,  691,  691,  691,  691,  691,  692,
+       58,   51,   50,   49,   43,  692,  693,  693,   42,   41,
+       35,   33,  693,  694,  694,   31,   27,    0,  694,  694,
+      695,  695,  695,  695,  696,  696,  696,  696,  696,  696,
+      696,  696,  697,  697,  697,  697,  697,  697,  697,  698,
+      698,  698,  698,    0,  698,  698,  698,  699,  699,  699,
+      699,  699,  699,  699,  699,  700,  700,  700,  700,  701,
+      701,  701,  701,  701,  701,  701,  701,  702,  702,  702,
+      702,  702,  702,  702,  703,  703,  703,  703,    0,  703,
+
+      703,  703,  704,  704,  704,  704,  704,  704,  704,  704,
+      705,  705,    0,  705,  705,  705,  705,  706,  706,  706,
+      706,  706,  706,  706,  706,  707,  707,  707,  707,  707,
+      707,  707,  707,  708,  708,    0,  708,  708,  708,  708,
+      709,  709,    0,    0,    0,    0,  709,  710,  710,  710,
+      710,    0,    0,  710,  711,  711,  711,  711,    0,  711,
+      711,  711,  712,  712,  712,  712,    0,    0,  712,  713,
+      713,  713,  713,    0,  713,  713,  713,  714,  714,  714,
+      714,  714,  714,  714,  715,  715,  715,  715,  715,  715,
+      715,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  681,  681,  681,
+      681,  681
+    } ;
+
+extern int lexc_flex_debug;
+int lexc_flex_debug = 0;
+
+static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up lexctext */ \
+yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
+(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
+(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
+yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
+++(yy_lp); \
+goto find_rule; \
+}
+
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() ((yy_more_flag) = 1)
+#define YY_MORE_ADJ (yy_more_len)
+#define YY_RESTORE_YY_MORE_OFFSET
+char *lexctext;
+#line 1 "lexc.l"
+/*   Foma: a finite-state toolkit and library.                                 */
+/*   Copyright © 2008-2015 Mans Hulden                                         */
+/*   This file is part of foma.                                                */
+/*   Licensed under the Apache License, Version 2.0 (the "License");           */
+/*   you may not use this file except in compliance with the License.          */
+/*   You may obtain a copy of the License at                                   */
+/*      http://www.apache.org/licenses/LICENSE-2.0                             */
+/*   Unless required by applicable law or agreed to in writing, software       */
+/*   distributed under the License is distributed on an "AS IS" BASIS,         */
+/*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
+/*   See the License for the specific language governing permissions and       */
+/*   limitations under the License.                                            */
+#define YY_NO_INPUT 1
+
+#line 25 "lexc.l"
+#include <stdio.h>
+#include "foma.h"
+#include "lexc.h"
+
+#define SOURCE_LEXICON 0
+#define TARGET_LEXICON 1
+#define YY_USER_ACTION lexccolumn += lexcleng;
+static int lexentries;
+extern int lexclex();
+static struct defined_networks *olddefines;
+extern int my_yyparse(char *my_string, int lineno, struct defined_networks *defined_nets, struct defined_functions *defined_funcs);
+extern struct fsm *current_parse;
+static char *tempstr;
+int lexccolumn = 0;
+
+#ifndef ORIGINAL
+int verbose_lexc_ = 1;
+#endif
+
+struct fsm *fsm_lexc_parse_string(char *string, int verbose) {
+
+   olddefines = g_defines;
+   YY_BUFFER_STATE my_string_buffer;
+   my_string_buffer = lexc_scan_string(string);
+   lexentries = -1;
+   lexclineno = 1;
+   lexc_init();
+   if (lexclex() != 1) {
+     if (lexentries != -1) {
+         printf("%i\n",lexentries);
+     }       
+   } 
+   lexc_delete_buffer(my_string_buffer);
+   g_defines = olddefines;
+   return(lexc_to_fsm());
+}
+
+struct fsm *fsm_lexc_parse_file(char *filename, int verbose) {
+  char *mystring;
+  mystring = file_to_mem(filename);
+  return(fsm_lexc_parse_string(mystring, verbose));
+}
+
+void lexc_trim(char *s) {
+  /* Remove trailing ; and = and space and initial space */
+  int i,j;
+  for (i = strlen(s)-1; *(s+i) == ';' || *(s+i) == '=' || *(s+i) == ' ' || *(s+i) == '\t'; i--)
+    *(s+i) = '\0';  
+  for (i=0; *(s+i) == ' ' || *(s+i) == '\t' || *(s+i) == '\n'; i++) {
+  }
+  for (j=0; *(s+i) != '\0'; i++, j++) {
+    *(s+j) = *(s+i);
+  }
+  *(s+j) = *(s+i);  
+}
+
+/* Nonreserved = anything except ; < > ! or space */
+
+#line 1390 "lex.lexc.c"
+
+#define INITIAL 0
+#define MCS 1
+#define LEXICON 2
+#define DEF 3
+#define LEXENTRIES 4
+#define INSIDEREGEX 5
+#define REGEX 6
+#define REGEXB 7
+#define REGEXQ 8
+#define DEFREGEX 9
+#define DEFREGEXB 10
+#define DEFREGEXQ 11
+#define EATUPINFO 12
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int lexclex_destroy (void );
+
+int lexcget_debug (void );
+
+void lexcset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE lexcget_extra (void );
+
+void lexcset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *lexcget_in (void );
+
+void lexcset_in  (FILE * in_str  );
+
+FILE *lexcget_out (void );
+
+void lexcset_out  (FILE * out_str  );
+
+int lexcget_leng (void );
+
+char *lexcget_text (void );
+
+int lexcget_lineno (void );
+
+void lexcset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+/*extern "C"*/ int lexcwrap (void );
+#else
+extern int lexcwrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( lexctext, lexcleng, 1, lexcout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( lexcin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( lexcin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, lexcin))==0 && ferror(lexcin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(lexcin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int lexclex (void);
+
+#define YY_DECL int lexclex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after lexctext and lexcleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+#line 94 "lexc.l"
+
+
+ /* Files begin with one of these three identifiers */
+#line 1591 "lex.lexc.c"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+        /* Create the reject buffer large enough to save one state per allowed character. */
+        if ( ! (yy_state_buf) )
+            (yy_state_buf) = (yy_state_type *)lexcalloc(YY_STATE_BUF_SIZE  );
+            if ( ! (yy_state_buf) )
+                YY_FATAL_ERROR( "out of dynamic memory in lexclex()" );
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! lexcin )
+			lexcin = stdin;
+
+		if ( ! lexcout )
+			lexcout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			lexcensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				lexc_create_buffer(lexcin,YY_BUF_SIZE );
+		}
+
+		lexc_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		(yy_more_len) = 0;
+		if ( (yy_more_flag) )
+			{
+			(yy_more_len) = (yy_c_buf_p) - (yytext_ptr);
+			(yy_more_flag) = 0;
+			}
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of lexctext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+
+		(yy_state_ptr) = (yy_state_buf);
+		*(yy_state_ptr)++ = yy_current_state;
+
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 682 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			*(yy_state_ptr)++ = yy_current_state;
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 2292 );
+
+yy_find_action:
+		yy_current_state = *--(yy_state_ptr);
+		(yy_lp) = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+		for ( ; ; ) /* until we find what rule we matched */
+			{
+			if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
+				{
+				yy_act = yy_acclist[(yy_lp)];
+				if ( yy_act & YY_TRAILING_HEAD_MASK ||
+				     (yy_looking_for_trail_begin) )
+					{
+					if ( yy_act == (yy_looking_for_trail_begin) )
+						{
+						(yy_looking_for_trail_begin) = 0;
+						yy_act &= ~YY_TRAILING_HEAD_MASK;
+						break;
+						}
+					}
+				else if ( yy_act & YY_TRAILING_MASK )
+					{
+					(yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
+					(yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
+					}
+				else
+					{
+					(yy_full_match) = yy_cp;
+					(yy_full_state) = (yy_state_ptr);
+					(yy_full_lp) = (yy_lp);
+					break;
+					}
+				++(yy_lp);
+				goto find_rule;
+				}
+			--yy_cp;
+			yy_current_state = *--(yy_state_ptr);
+			(yy_lp) = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 97 "lexc.l"
+{
+  BEGIN(MCS);
+}
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 101 "lexc.l"
+{
+    BEGIN(DEF);
+}
+	YY_BREAK
+/* This line needs to be above the space glob */
+/* otherwise spaces get eaten up in a regex */
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 107 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 111 "lexc.l"
+{ }
+	YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+#line 112 "lexc.l"
+{ lexclineno++; lexccolumn = 1;}
+	YY_BREAK
+/* Multichar definitions */
+/* A Multichar definition can contain anything except nonescaped space */
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 116 "lexc.l"
+{
+  lexc_add_mc(lexctext);
+}
+	YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 120 "lexc.l"
+{
+  lexc_trim(lexctext+8);
+  if (lexentries != -1) {
+    printf("%i, ",lexentries);
+  }
+  printf("%s...",lexctext+8);
+  fflush(stdout);
+  lexentries = 0;
+  lexc_set_current_lexicon(lexctext+8, SOURCE_LEXICON);
+  BEGIN(LEXENTRIES);
+}
+	YY_BREAK
+/* Grab info string */
+case 8:
+YY_RULE_SETUP
+#line 133 "lexc.l"
+{
+  BEGIN(LEXENTRIES);
+}
+	YY_BREAK
+/* Target followed by info string */
+case 9:
+/* rule 9 can match eol */
+YY_RULE_SETUP
+#line 137 "lexc.l"
+{
+    lexc_trim(lexctext);
+    lexc_set_current_lexicon(lexctext, TARGET_LEXICON);
+    lexc_add_word();
+    lexc_clear_current_word();
+    lexentries++;
+    if (lexentries %10000 == 0) {
+      printf("%i...",lexentries);
+      fflush(stdout);
+    }
+    BEGIN(EATUPINFO);
+}
+	YY_BREAK
+/* Regular entries contain anything (not starting with <) and end in a nonescaped SPACE */
+case 10:
+/* rule 10 can match eol */
+YY_RULE_SETUP
+#line 152 "lexc.l"
+{
+      lexc_set_current_word(lexctext);
+}
+	YY_BREAK
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+#line 157 "lexc.l"
+{
+    //printf("[%s]\n", lexctext);
+    lexc_trim(lexctext);
+    lexc_set_current_lexicon(lexctext, TARGET_LEXICON);
+    lexc_add_word();
+    lexc_clear_current_word();
+    lexentries++;
+    if (lexentries %10000 == 0) {
+      printf("%i...",lexentries);
+      fflush(stdout);
+    }
+}
+	YY_BREAK
+/* A REGEX entry begins and ends with a < , > */
+case 12:
+YY_RULE_SETUP
+#line 171 "lexc.l"
+{
+  BEGIN(REGEX);
+}
+	YY_BREAK
+/* \076 = > */
+case 13:
+YY_RULE_SETUP
+#line 175 "lexc.l"
+{
+    *(lexctext+lexcleng-1) = ';';
+    if (my_yyparse(lexctext, lexclineno, g_defines, NULL) == 0) {
+       lexc_set_network(current_parse);
+    }    
+    BEGIN(LEXENTRIES);
+}
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 183 "lexc.l"
+{
+  BEGIN(REGEXB);
+  yymore();
+}
+	YY_BREAK
+case 15:
+/* rule 15 can match eol */
+YY_RULE_SETUP
+#line 187 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 190 "lexc.l"
+{
+  BEGIN(REGEX);
+  yymore();
+}
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 194 "lexc.l"
+{
+  BEGIN(REGEXQ);
+  yymore();
+}
+	YY_BREAK
+case 18:
+/* rule 18 can match eol */
+YY_RULE_SETUP
+#line 198 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 201 "lexc.l"
+{
+  BEGIN(REGEX);
+  yymore();
+}
+	YY_BREAK
+case 20:
+/* rule 20 can match eol */
+YY_RULE_SETUP
+#line 205 "lexc.l"
+{
+    lexc_trim(lexctext);
+    tempstr = xxstrdup(lexctext);
+    BEGIN(DEFREGEX);
+}
+	YY_BREAK
+/* \073 = ; */
+case 21:
+YY_RULE_SETUP
+#line 211 "lexc.l"
+{
+    if (my_yyparse(lexctext, lexclineno, g_defines, NULL) == 0) {
+      add_defined(g_defines, fsm_topsort(fsm_minimize(current_parse)),tempstr);
+    }
+    xxfree(tempstr);
+    BEGIN(DEF);
+}
+	YY_BREAK
+case 22:
+/* rule 22 can match eol */
+YY_RULE_SETUP
+#line 218 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 221 "lexc.l"
+{
+  BEGIN(DEFREGEXB);
+  yymore();
+}
+	YY_BREAK
+case 24:
+/* rule 24 can match eol */
+YY_RULE_SETUP
+#line 225 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 228 "lexc.l"
+{
+  BEGIN(DEFREGEX);
+  yymore();
+}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 232 "lexc.l"
+{
+  BEGIN(DEFREGEXQ);
+  yymore();
+}
+	YY_BREAK
+case 27:
+/* rule 27 can match eol */
+YY_RULE_SETUP
+#line 236 "lexc.l"
+{
+  yymore();
+}
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 239 "lexc.l"
+{
+  BEGIN(DEFREGEX);
+  yymore();
+}
+	YY_BREAK
+case 29:
+/* rule 29 can match eol */
+YY_RULE_SETUP
+#line 243 "lexc.l"
+{  /* printf ("Comment: [%s]\n",lexctext); */  }
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 245 "lexc.l"
+{ printf("\n***Syntax error on line %i column %i at '%s'\n",lexclineno,lexccolumn,lexctext); return 1;}
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 246 "lexc.l"
+ECHO;
+	YY_BREAK
+#line 1984 "lex.lexc.c"
+			case YY_STATE_EOF(INITIAL):
+			case YY_STATE_EOF(MCS):
+			case YY_STATE_EOF(LEXICON):
+			case YY_STATE_EOF(DEF):
+			case YY_STATE_EOF(LEXENTRIES):
+			case YY_STATE_EOF(INSIDEREGEX):
+			case YY_STATE_EOF(REGEX):
+			case YY_STATE_EOF(REGEXB):
+			case YY_STATE_EOF(REGEXQ):
+			case YY_STATE_EOF(DEFREGEX):
+			case YY_STATE_EOF(DEFREGEXB):
+			case YY_STATE_EOF(DEFREGEXQ):
+			case YY_STATE_EOF(EATUPINFO):
+				yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed lexcin at a new source and called
+			 * lexclex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = lexcin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( lexcwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * lexctext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of lexclex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			lexcrestart(lexcin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) lexcrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	(yy_state_ptr) = (yy_state_buf);
+	*(yy_state_ptr)++ = yy_current_state;
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 50);
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 682 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		*(yy_state_ptr)++ = yy_current_state;
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	register YY_CHAR yy_c = 50;
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 682 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 681);
+	if ( ! yy_is_jam )
+		*(yy_state_ptr)++ = yy_current_state;
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					lexcrestart(lexcin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( lexcwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve lexctext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void lexcrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        lexcensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            lexc_create_buffer(lexcin,YY_BUF_SIZE );
+	}
+
+	lexc_init_buffer(YY_CURRENT_BUFFER,input_file );
+	lexc_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void lexc_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		lexcpop_buffer_state();
+	 *		lexcpush_buffer_state(new_buffer);
+     */
+	lexcensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	lexc_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (lexcwrap()) processing, but the only time this flag
+	 * is looked at is after lexcwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void lexc_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	lexcin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE lexc_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) lexcalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in lexc_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) lexcalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in lexc_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	lexc_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with lexc_create_buffer()
+ * 
+ */
+    void lexc_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		lexcfree((void *) b->yy_ch_buf  );
+
+	lexcfree((void *) b  );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a lexcrestart() or at EOF.
+ */
+    static void lexc_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	lexc_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then lexc_init_buffer was _probably_
+     * called from lexcrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void lexc_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		lexc_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void lexcpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	lexcensure_buffer_stack();
+
+	/* This block is copied from lexc_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from lexc_switch_to_buffer. */
+	lexc_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void lexcpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	lexc_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		lexc_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void lexcensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)lexcalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in lexcensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)lexcrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in lexcensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE lexc_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) lexcalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in lexc_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	lexc_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to lexclex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       lexc_scan_bytes() instead.
+ */
+YY_BUFFER_STATE lexc_scan_string (yyconst char * yystr )
+{
+    
+	return lexc_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to lexclex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE lexc_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) lexcalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in lexc_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = lexc_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in lexc_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up lexctext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		lexctext[lexcleng] = (yy_hold_char); \
+		(yy_c_buf_p) = lexctext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		lexcleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int lexcget_lineno  (void)
+{
+        
+    return lexclineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *lexcget_in  (void)
+{
+        return lexcin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *lexcget_out  (void)
+{
+        return lexcout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int lexcget_leng  (void)
+{
+        return lexcleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *lexcget_text  (void)
+{
+        return lexctext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void lexcset_lineno (int  line_number )
+{
+    
+    lexclineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see lexc_switch_to_buffer
+ */
+void lexcset_in (FILE *  in_str )
+{
+        lexcin = in_str ;
+}
+
+void lexcset_out (FILE *  out_str )
+{
+        lexcout = out_str ;
+}
+
+int lexcget_debug  (void)
+{
+        return lexc_flex_debug;
+}
+
+void lexcset_debug (int  bdebug )
+{
+        lexc_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from lexclex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+    (yy_state_buf) = 0;
+    (yy_state_ptr) = 0;
+    (yy_full_match) = 0;
+    (yy_lp) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    lexcin = stdin;
+    lexcout = stdout;
+#else
+    lexcin = (FILE *) 0;
+    lexcout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * lexclex_init()
+     */
+    return 0;
+}
+
+/* lexclex_destroy is for both reentrant and non-reentrant scanners. */
+int lexclex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		lexc_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		lexcpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	lexcfree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    lexcfree ( (yy_state_buf) );
+    (yy_state_buf)  = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * lexclex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *lexcalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *lexcrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void lexcfree (void * ptr )
+{
+	free( (char *) ptr );	/* see lexcrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 246 "lexc.l"
diff --git a/back-ends/foma/cpp-version/lex.yy.cc b/back-ends/foma/cpp-version/lex.yy.cc
new file mode 100644
index 0000000..cd0d680
--- /dev/null
+++ b/back-ends/foma/cpp-version/lex.yy.cc
@@ -0,0 +1,4209 @@
+
+#line 3 "lex.yy.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+     *       access to the local variable yy_act. Since yyless() is a macro, it would break
+     *       existing scanners that call yyless() from OUTSIDE yylex. 
+     *       One obvious solution it to make yy_act a global. I tried that, and saw
+     *       a 5% performance hit in a non-yylineno scanner, because yy_act is
+     *       normally declared as a register variable-- so it is not worth it.
+     */
+    #define  YY_LESS_LINENO(n) \
+            do { \
+                int yyl;\
+                for ( yyl = n; yyl < yyleng; ++yyl )\
+                    if ( yytext[yyl] == '\n' )\
+                        --yylineno;\
+            }while(0)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void yypop_buffer_state (yyscan_t yyscanner );
+
+static void yyensure_buffer_stack (yyscan_t yyscanner );
+static void yy_load_buffer_state (yyscan_t yyscanner );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (size_t) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 129
+#define YY_END_OF_BUFFER 130
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[574] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,  130,  128,   10,  126,  127,  128,
+      128,  108,  128,  124,   46,  118,  119,  110,  109,   97,
+      105,  128,  100,   95,  122,   63,   46,   64,  128,  113,
+      104,  114,  128,   48,   89,  128,  123,   57,  128,  128,
+      128,  128,  128,  128,  128,  128,  128,  128,  129,  129,
+      129,  129,  129,   18,  129,  129,  129,  129,  129,  129,
+      129,  129,   15,   10,  126,  127,    0,  125,    0,   19,
+        0,    0,    0,  107,  106,   46,    0,    0,    0,    0,
+       46,   45,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,   98,   66,    0,
+        0,    0,   49,   50,    0,    0,   53,   51,  111,    0,
+        0,  112,    0,   91,    0,  121,  120,   68,   62,   82,
+       88,   78,    0,    0,   86,   74,    0,    0,    0,    0,
+       93,   92,    6,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   90,   57,   96,   21,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   17,    0,
+        0,    0,    0,    0,    0,   13,    0,    0,    0,    0,
+        0,    0,   14,    0,    0,    0,    0,    0,   16,    0,
+
+        0,   46,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   76,   47,   65,
+       99,   59,   60,   58,   61,  101,  103,   70,   80,    0,
+       72,   84,    0,    0,    0,   52,  102,    9,    8,    0,
+       22,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    1,    0,    1,    0,    0,
+        0,    0,    1,    0,    0,    0,    0,    1,    0,    0,
+        0,   94,    0,   54,   55,   20,   56,  124,  123,  117,
+      115,  116,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       67,    0,   69,    0,    0,   83,   79,    0,   87,    0,
+       75,    0,    0,    2,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   34,    0,    0,    0,    0,    0,   27,
+        0,    0,    0,    0,    0,    0,    1,    0,    0,    0,
+        0,    1,    0,    0,    0,    0,    1,    0,    0,    0,
+        0,    1,    0,    0,    0,    0,    0,    1,    0,    0,
+        0,    0,    1,    0,    0,    0,    0,    1,    0,    0,
+        0,    0,    0,   77,   71,   81,   73,   85,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        1,    0,    0,    0,    0,    1,    0,    0,    0,    0,
+        1,    0,    0,    0,    0,    1,    0,    0,    0,    0,
+        1,    0,    0,    0,    0,    1,    0,    0,    0,   11,
+        0,    0,   12,    0,    0,    3,    0,    0,    7,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        4,    0,    0,    0,    0,    0,    0,    0,   43,    0,
+        0,    0,    0,    0,    0,    0,    0,   26,    0,    0,
+
+        5,    0,    0,    0,    0,    0,   33,    0,   44,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   38,
+        0,   39,    0,   32,   41,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   30,    0,    0,    0,   40,
+        0,   35,   42,    0,    0,    0,    0,    0,    0,   28,
+        0,   31,    0,    0,    0,   24,    0,    0,    0,    0,
+        0,    0,    0,   36,    0,   25,    0,   29,    0,   23,
+        0,   37,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    6,    7,    8,    9,   10,   11,   12,   13,
+       14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
+       21,   21,   21,   21,   21,   21,   21,   24,   25,   26,
+       27,   28,   29,   30,   12,   12,   12,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,   12,   31,   32,
+       12,   12,   33,   12,   12,   12,   12,   12,   12,   12,
+       34,   35,   36,   37,   38,   39,   40,   41,   42,   43,
+
+       44,   45,   46,   12,   47,   12,   48,   49,   50,   51,
+       52,   53,   54,   55,   56,   57,   58,   12,   59,   60,
+       61,   12,   62,   63,   64,   65,   66,   67,   68,   69,
+       70,   71,   72,   73,   74,   75,   76,   77,   77,   77,
+       77,   77,   77,   77,   77,   78,   77,   79,   77,   77,
+       80,   81,   77,   77,   77,   77,   77,   77,   77,   82,
+       77,   77,   83,   84,   85,   77,   86,   87,   88,   89,
+       77,   90,   77,   77,   77,   77,   77,   77,   77,   77,
+       91,   77,   77,   77,   92,   93,   94,   77,   77,   77,
+       77,   95,   95,   96,   97,   98,   98,   98,   98,   98,
+
+       98,   98,   98,   98,   98,   99,  100,  100,  100,  100,
+      100,  100,  100,  100,  100,  100,  100,  100,  100,  100,
+      100,  100,  100,  101,  101,  102,  103,  103,  103,  103,
+      103,  103,  103,  103,  103,  103,  103,  103,  103,  104,
+      104,  104,  104,  104,  104,  104,  104,   77,   77,   77,
+       77,   77,   77,   77,   77
+    } ;
+
+static yyconst flex_int32_t yy_meta[106] =
+    {   0,
+        1,    1,    2,    1,    1,    1,    3,    4,    1,    5,
+        1,    5,    6,    7,    1,    1,    1,    1,    1,    1,
+        5,    5,    5,    1,    1,    1,    5,    1,    5,    1,
+        5,    5,    5,    1,    1,    1,    1,    1,    1,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    1,    1,    8,    1,    1,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,   10,    5,    5,    5,    5,    5,    5,
+
+        5,    5,    5,    5,   11
+    } ;
+
+static yyconst flex_int16_t yy_base[714] =
+    {   0,
+        0,    0,    0,    0,   99,  198, 1517, 1516,  290,  381,
+      472,  563, 1508, 1507, 1518, 4440,  105, 1514, 1512, 1512,
+      111,   90,   25, 4440,  121,  124, 4440, 4440, 4440, 1497,
+     1485,  660,   95, 4440,   89,  115,  134, 1482,  298,  117,
+      120, 4440,  285,  206, 4440,  232, 1448, 4440,    0,  138,
+      160,    0,  158,    0,    0,  653,    0,    0, 4440,  302,
+      755,    0,    0, 4440,  323,  858,    0,    0,  334,  950,
+        0,    0, 4440,  106, 1440, 1418, 1418, 4440,  312, 4440,
+     1042,    0,    0, 4440, 4440,  407,    0,    0,    0,  392,
+      429, 4440,    0,  153,  162,    0,  161,    0,    0, 1080,
+
+        0,    0, 1382,  119, 1379,  120, 1333, 4440, 1377, 1387,
+     1386, 1385, 4440, 4440, 1384, 1382, 4440, 4440, 4440, 1381,
+     1380, 4440, 1379, 1377, 1376, 4440, 4440,   84, 4440, 4440,
+     4440, 4440,    0, 1367, 1376, 4440, 1349, 1335, 1321,    0,
+     4440, 1315,  136,  237,  299,  317, 1336,  300, 1299, 1293,
+     1297, 1289,  273, 1304, 1291, 1261, 1267,  514,  695,  705,
+      716, 1244, 4440, 4440, 4440,    0,    0,  224,  444, 1303,
+      437,    0,  514,  498,    0,    0,    0,  755, 4440, 1182,
+        0,    0,    0,    0,  524, 4440, 1285,    0,    0,    0,
+        0,  574, 4440, 1377,    0,    0,    0,    0, 4440,    0,
+
+        0,  675,    0,  157,  348,    0,  496,    0,    0, 1404,
+        0,    0,    0,    0,    0,  429,  440,  795,  512,  121,
+      507, 1291, 1290, 1275,   99, 1288,  245, 4440, 4440, 4440,
+     4440, 4440, 4440, 4440, 4440, 4440, 4440, 4440, 4440, 1294,
+     4440, 4440, 1292, 1238, 1240, 4440, 4440,  323,  422,  869,
+     4440, 1253, 1246, 1253, 1241, 1279, 1251,  639, 1241, 1272,
+     1225, 1228, 1225, 1240, 1240, 4440,  799,  809,  890,  911,
+      952,  993, 1276, 1134, 1213, 1225, 1236,    0, 1287, 1338,
+     1506, 4440, 1182, 4440, 4440, 4440, 4440, 4440, 4440, 4440,
+     4440, 4440,  258,    0,    0,    0,    0,    0,    0,  587,
+
+      626, 1245,  685,    0,  992,  784,    0,    0,    0,    0,
+     4440, 1233, 4440, 1232, 1231, 4440, 4440, 1230, 4440, 1229,
+     4440,  820,  861, 4440,    0, 1185, 1234,  682,  760,  655,
+     1195,  555, 1171, 4440, 1158, 1156, 1170, 1161, 1154, 4440,
+     1166, 1161, 1161, 1158, 1156, 1004, 1122, 1516, 1526, 1536,
+     1578, 1588, 1638, 1648, 1658, 1668, 1710, 1720, 1770, 1780,
+     1790, 1202, 1800, 1842, 1852, 1201, 1902, 1912, 1922, 1932,
+     1974, 1984, 1200, 2034, 2044, 2054, 2064, 1199, 2106, 2116,
+     2166, 1109,    0, 4440, 4440, 4440, 4440, 4440, 1316, 2268,
+        0,    0, 1328, 2360,    0,    0, 1193, 1192,    0,  763,
+
+      982, 1150, 1144, 1143, 1147, 1146, 1140, 1151, 1146, 1132,
+     1137, 1143, 1106, 1090, 1089, 1086, 1099, 1101, 1099, 1446,
+     1456, 2178, 2188, 2229, 2300, 2310, 2320, 2362, 2391, 2453,
+     2464, 2474, 2494, 2515, 2536, 2577, 2596, 2606, 2618, 2647,
+     2659, 2709, 2721, 2731, 2750, 2772, 2791, 2834, 2853, 4440,
+        0,    0, 4440,    0,    0, 4440,    0, 1132, 4440, 1087,
+     1046, 1036, 1035, 1034, 1034, 1028,  383, 1038, 1034, 1024,
+     1024, 1028, 1013, 1030, 1056, 1025, 1012,    0,    0, 1056,
+     4440, 1021, 1007, 1013,  954,  961,  987,  942, 4440,  985,
+      946,  927,  926,  941,  922,  929,  932, 4440,  934,  937,
+
+     4440,  927,  961,  926,  959,  922, 4440,  957, 4440,  956,
+      921,  920,  919,  833,  840,  836,  830,  820,  823, 4440,
+      820, 4440,  851, 4440, 4440,  769,  753,  743,  775,  713,
+      753,  748,  703,  665,  676, 4440,  663,  649,  645, 4440,
+      297, 4440, 4440,  689,  649,  644,  650,  676,  555, 4440,
+      553, 4440,  551,  544,  536, 4440,  478,  466,  507,  462,
+      487,  390,  343, 4440,  290, 4440,  301, 4440,  210, 4440,
+      241, 4440, 4440, 2957, 2968, 2979, 2990, 3001, 3012, 3020,
+     3024, 3030, 3041, 3052, 3063, 3074, 3085, 3096, 3104, 3115,
+     3126, 3137, 3148, 3159, 3170, 3181, 3192, 3203, 3211, 3222,
+
+      240, 3233, 3244, 3255, 3266, 3270, 3276, 3287, 3298, 3309,
+     3320, 3331, 3342, 3353, 3364, 3375, 3386, 3397, 3408, 3416,
+     3427, 3438, 3449, 3460, 3471, 3482, 3493, 3504, 3515, 3526,
+     3537, 3548,  111, 3559, 3570, 3581, 3592, 3603, 3614, 3625,
+     3636, 3647, 3658, 3669, 3680, 3691, 3702, 3713, 3724, 3735,
+     3746, 3757, 3768, 3779, 3790, 3801, 3812, 3823, 3834, 3845,
+     3856, 3867, 3878, 3889, 3900, 3911, 3922, 3933, 3944, 3955,
+     3966, 3977, 3988, 3999, 4010, 4021, 4032, 4043, 4054, 4065,
+     4076, 4087, 4098, 4109, 4120, 4131, 4142, 4153, 4164, 4175,
+     4186, 4197, 4208, 4219, 4230, 4241, 4252, 4263, 4274, 4285,
+
+     4296, 4307, 4318, 4329, 4340, 4351, 4362, 4373, 4384, 4395,
+     4406, 4417, 4428
+    } ;
+
+static yyconst flex_int16_t yy_def[714] =
+    {   0,
+      573,    1,  574,  574,  575,  575,  574,  574,  576,  576,
+      577,  577,  574,  574,  573,  573,  573,  573,  573,  578,
+      579,  573,  580,  573,  581,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  581,  573,  573,  573,
+      573,  573,  573,  573,  573,  582,  573,  573,  583,  583,
+      583,  583,  583,  583,  584,  585,  586,  587,  573,  588,
+      588,  589,  590,  573,  591,  591,  592,  593,  594,  594,
+      595,  596,  573,  573,  573,  573,  597,  573,  598,  573,
+      598,  599,  600,  573,  573,  601,  602,  603,  604,  605,
+      606,  573,  607,  607,  607,  607,  607,  607,  608,  609,
+
+      610,  611,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  612,  573,  573,  573,  573,  573,  573,  613,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  614,  615,  616,
+      617,  573,  573,  573,  573,  607,  607,  607,  607,  607,
+      607,  607,  607,  607,  607,  607,  618,  619,  573,  619,
+      620,  621,  180,  622,  623,  573,  623,  624,  625,  187,
+      626,  627,  573,  627,  628,  629,  194,  630,  573,  631,
+
+      632,  633,  634,  634,  634,  634,  634,  634,  635,  636,
+      637,  638,  639,  640,  641,  641,  641,  641,  641,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  642,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  643,  643,  644,  645,
+      646,  644,  643,  647,  648,  649,  650,  651,  652,  653,
+      654,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  641,  655,  656,  657,  658,  659,  659,  659,
+
+      659,  659,  659,  659,  659,  659,  659,  659,  660,  661,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  662,  663,  573,  664,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  665,  665,  666,  667,  668,
+      666,  666,  669,  670,  671,  672,  672,  673,  674,  675,
+      666,  665,  669,  670,  671,  665,  666,  666,  669,  670,
+      671,  669,  666,  676,  677,  678,  673,  672,  679,  680,
+      681,  573,  682,  573,  573,  573,  573,  573,  683,  683,
+      684,  685,  686,  686,  687,  688,  689,  573,  690,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  691,
+      691,  692,  693,  694,  692,  692,  695,  696,  697,  698,
+      698,  699,  700,  701,  692,  692,  695,  696,  697,  695,
+      695,  702,  703,  704,  699,  699,  705,  706,  707,  573,
+      708,  709,  573,  710,  711,  573,  712,  713,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  708,  710,  712,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,    0,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573
+    } ;
+
+static yyconst flex_int16_t yy_nxt[4546] =
+    {   0,
+       16,   17,   18,   19,   17,   20,   21,   20,   22,   23,
+       24,   25,   26,   27,   28,   29,   30,   31,   32,   33,
+       25,   25,   25,   34,   35,   36,   37,   38,   25,   39,
+       25,   25,   25,   40,   41,   42,   43,   44,   45,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   25,   25,   25,   25,   25,
+       25,   46,   47,   16,   48,   16,   16,   16,   16,   16,
+       16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   16,   49,   50,   51,   52,   53,   54,
+
+       55,   56,   57,   58,   16,   59,   74,   74,   84,   74,
+       74,  238,  319,  239,  124,  202,  320,   80,   85,   87,
+       87,   87,   87,   87,   87,   88,   88,   88,   89,  125,
+       90,  126,  128,   92,  311,  140,  221,  224,  127,  141,
+       91,  103,  129,   90,  130,  225,   92,  226,  222,  104,
+      312,  105,   80,  106,  142,   91,  143,  143,  143,  202,
+       91,  131,   91,   91,   91,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   61,   61,   61,   61,   61,   61,   62,
+
+       62,   62,   63,   59,   59,   81,   81,   81,   81,   81,
+       81,   82,   82,   82,   83,   93,   94,   95,   96,   97,
+       98,   99,  100,  101,  102,  107,   91,  163,   93,   94,
+       95,   96,   97,   98,   99,  100,  101,  102,  147,  164,
+      165,  573,  573,  573,  202,  148,  573,  149,   80,  150,
+      151,  573,  152,  572,  153,  154,  155,  248,  248,  248,
+      573,  156,  571,  157,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   61,   61,   61,   61,   61,   61,   62,   62,
+
+       62,   63,   59,   59,  133,  143,  143,  143,  179,  550,
+      144,  322,  145,  570,  323,  134,  259,  283,  199,  249,
+      249,  249,  260,  135,  261,  136,  159,  159,  159,  159,
+      159,  159,  160,  160,  160,  161,  186,  250,  250,  250,
+      551,  569,  252,  248,  248,  248,  146,  193,  253,  254,
+      202,   91,  137,  138,  139,  568,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   66,   66,   66,   66,   66,   66,
+       67,   67,   67,   68,   59,  489,  180,  180,  180,  180,
+
+      180,  180,  181,  181,  181,  182,   81,   81,   81,   81,
+       81,   81,   82,   82,   82,   83,   90,  187,  187,  187,
+      187,  187,  187,  188,  188,  188,  189,  573,  194,  194,
+      194,  194,  194,  194,  195,  195,  195,  196,   90,   91,
+      490,   92,  249,  249,  249,  567,   91,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   66,   66,   66,   66,   66,
+       66,   67,   67,   67,   68,   59,   87,   87,   87,   87,
+       87,   87,   88,   88,   88,   89,  573,  573,  202,  566,
+
+       91,  203,  204,  205,  206,  207,  208,  209,  210,  211,
+      212,  113,  114,  565,  284,  285,   91,  573,  573,  564,
+      313,  563,   91,   93,   94,   95,   96,   97,   98,   99,
+      100,  101,  102,   91,  314,  562,  315,  186,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   70,   70,   70,   70,
+       70,   70,   71,   71,   71,   72,   59,  266,  573,  290,
+      573,  573,  573,  573,  561,  286,  573,  193,  287,  202,
+      291,  292,  560,  573,  234,  573,  573,  407,  129,  288,
+
+      289,  288,  289,  559,  573,  558,  557,  408,  159,  159,
+      159,  159,  159,  159,  160,  160,  160,  161,  187,  187,
+      187,  187,  187,  187,  188,  188,  188,  189,  202,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   70,   70,   70,
+       70,   70,   70,   71,   71,   71,   72,  110,  194,  194,
+      194,  194,  194,  194,  195,  195,  195,  196,  111,  112,
+      573,  113,  114,  336,   90,  337,  328,  202,  556,  555,
+      115,  116,  554,  573,  573,  117,  338,  158,  329,  402,
+
+      553,  552,  549,  403,  118,  404,  119,  158,  114,  548,
+      405,  120,  121,  547,  122,  546,  545,  113,  158,  123,
+      168,  169,  170,  170,  170,  171,  172,  173,  174,  175,
+      175,  175,  175,  175,  175,  175,  175,  175,  175,  175,
+      175,  175,  175,  175,  175,  175,  175,  175,  175,  175,
+      175,  175,  175,  175,  175,  175,  175,  573,  268,  544,
+      543,  179,  573,  573,  400,  542,  541,  400,  273,  203,
+      204,  205,  206,  207,  208,  209,  210,  211,  212,  278,
+      401,  401,  401,  401,  401,  401,  202,  540,  539,  269,
+      269,  269,  269,  269,  269,  270,  270,  270,  271,  274,
+
+      274,  274,  274,  274,  274,  275,  275,  275,  276,  538,
+      279,  279,  279,  279,  279,  279,  280,  280,  280,  281,
+      537,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  180,
+      180,  180,  180,  180,  180,  181,  181,  181,  182,  178,
+      573,  573,  266,  536,  573,  573,  573,  573,  573,  573,
+      535,  534,  266,  328,  533,  573,  573,  573,  532,  573,
+      573,  573,  573,  573,  531,  329,  530,  529,   91,  250,
+      250,  250,  158,  159,  159,  159,  159,  159,  159,  160,
+
+      160,  160,  161,  159,  159,  159,  159,  159,  159,  160,
+      160,  160,  161,  158,  390,  390,  390,  390,  390,  390,
+      391,  391,  391,  392,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  573,  268,  158,  394,  394,  394,  394,  394,
+      394,  395,  395,  395,  396,  528,  527,  526,  525,  524,
+      523,  522,  521,  520,  273,  519,  518,  517,  516,  515,
+      514,  513,  512,  511,  269,  269,  269,  269,  269,  269,
+      270,  270,  270,  271,  202,  158,  510,  509,  508,  507,
+
+      506,  505,  401,  401,  401,  274,  274,  274,  274,  274,
+      274,  275,  275,  275,  276,  278,  192,  192,  192,  192,
+      192,  192,  192,  192,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,  192,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,  192,  573,  459,  279,  279,  279,  279,
+      279,  279,  280,  280,  280,  281,  268,  504,  573,  503,
+      502,  573,  501,  573,  500,  499,  573,  266,  498,  497,
+      496,  495,  573,  494,  493,  492,  573,  573,  573,  573,
+      573,  491,  488,  487,  486,  485,  484,  269,  269,  269,
+      269,  269,  269,  270,  270,  270,  271,  483,  159,  159,
+
+      159,  159,  159,  159,  160,  160,  160,  161,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,  158,  482,  481,  477,
+      476,  475,  474,  473,  472,  471,   79,  215,  216,  170,
+      170,  170,  217,  172,  218,  219,  175,  175,  175,  175,
+      175,  175,  175,  175,  175,  175,  175,  175,  175,  175,
+      175,  175,  175,  175,  175,  175,  175,  175,  175,  175,
+      175,  175,  175,  175,  573,  266,  470,  469,  468,  467,
+      466,  465,  464,  463,  462,  461,  460,  347,  457,  456,
+
+      119,  573,  573,  573,  573,  419,  418,  417,  416,  415,
+      414,  413,  412,  411,  410,  158,  159,  159,  159,  159,
+      159,  159,  160,  160,  160,  161,  409,  158,  348,  348,
+      348,  348,  348,  348,  349,  349,  349,  350,  158,  406,
+      399,  398,  388,  387,  386,  385,  384,  202,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  352,  382,  573,  345,
+      344,  343,  342,  341,  340,  339,  178,  573,  357,  158,
+      335,  334,  333,  332,  331,  330,  327,  326,  325,  362,
+
+      324,  321,  318,  317,  316,   91,  282,  353,  353,  353,
+      353,  353,  353,  354,  354,  354,  355,  265,  264,  358,
+      358,  358,  358,  358,  358,  359,  359,  359,  360,  450,
+      363,  363,  363,  363,  363,  363,  364,  364,  364,  365,
+      158,  453,  263,  262,  258,  257,  256,  255,  251,  247,
+      368,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  573,
+      245,  369,  369,  369,  369,  369,  369,  370,  370,  370,
+      371,  244,  243,  242,  241,  237,  236,  164,  235,  234,
+
+      233,  373,  232,  231,  230,  229,  228,  227,  223,  220,
+      390,  390,  390,  390,  390,  390,  391,  391,  391,  392,
+       78,   76,  394,  394,  394,  394,  394,  394,  395,  395,
+      395,  396,  374,  374,  374,  374,  374,  374,  375,  375,
+      375,  376,   75,  192,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,  192,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,  192,  192,  192,  192,  192,  192,  192,
+      192,  300,  301,  302,  302,  302,  303,  304,  305,  306,
+      307,  307,  307,  307,  307,  307,  307,  307,  307,  307,
+      307,  307,  307,  307,  307,  307,  307,  307,  307,  307,
+
+      307,  307,  307,  307,  307,  307,  307,  307,  158,  266,
+      162,  132,  109,  108,   78,   76,   75,  573,  158,  266,
+       73,   73,   64,   64,  573,  573,  573,  573,  158,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  158,  573,
+      159,  159,  159,  159,  159,  159,  160,  160,  160,  161,
+      159,  159,  159,  159,  159,  159,  160,  160,  160,  161,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  378,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  268,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  273,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  278,
+
+      379,  379,  379,  379,  379,  379,  380,  380,  380,  381,
+      269,  269,  269,  269,  269,  269,  270,  270,  270,  271,
+      274,  274,  274,  274,  274,  274,  275,  275,  275,  276,
+      279,  279,  279,  279,  279,  279,  280,  280,  280,  281,
+      158,  268,  573,  573,  573,  573,  573,  573,  573,  573,
+      158,  268,  573,  573,  573,  573,  573,  573,  573,  573,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      158,  573,  269,  269,  269,  269,  269,  269,  270,  270,
+      270,  271,  269,  269,  269,  269,  269,  269,  270,  270,
+      270,  271,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  347,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  352,  158,  573,  573,  573,  573,  573,  573,  573,
+      573,  357,  158,  573,  573,  573,  573,  573,  573,  573,
+      573,  362,  348,  348,  348,  348,  348,  348,  349,  349,
+      349,  350,  353,  353,  353,  353,  353,  353,  354,  354,
+      354,  355,  358,  358,  358,  358,  358,  358,  359,  359,
+      359,  360,  363,  363,  363,  363,  363,  363,  364,  364,
+      364,  365,  158,  362,  573,  573,  573,  573,  573,  573,
+      573,  573,  158,  368,  573,  573,  573,  573,  573,  573,
+      573,  573,  158,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  158,  573,  363,  363,  363,  363,  363,  363,
+      364,  364,  364,  365,  369,  369,  369,  369,  369,  369,
+      370,  370,  370,  371,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  373,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  378,  158,  573,  573,  573,  573,  573,
+      573,  573,  573,  268,  158,  573,  573,  573,  573,  573,
+      573,  573,  573,  347,  374,  374,  374,  374,  374,  374,
+      375,  375,  375,  376,  379,  379,  379,  379,  379,  379,
+      380,  380,  380,  381,  269,  269,  269,  269,  269,  269,
+      270,  270,  270,  271,  348,  348,  348,  348,  348,  348,
+
+      349,  349,  349,  350,  158,  352,  573,  573,  573,  573,
+      573,  573,  573,  573,  158,  357,  573,  573,  573,  573,
+      573,  573,  573,  573,  158,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  158,  573,  353,  353,  353,  353,
+      353,  353,  354,  354,  354,  355,  358,  358,  358,  358,
+      358,  358,  359,  359,  359,  360,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  268,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  268,  158,  573,  573,  573,
+      573,  573,  573,  573,  573,  347,  158,  573,  573,  573,
+      573,  573,  573,  573,  573,  352,  269,  269,  269,  269,
+
+      269,  269,  270,  270,  270,  271,  269,  269,  269,  269,
+      269,  269,  270,  270,  270,  271,  348,  348,  348,  348,
+      348,  348,  349,  349,  349,  350,  353,  353,  353,  353,
+      353,  353,  354,  354,  354,  355,  158,  357,  573,  573,
+      573,  573,  573,  573,  573,  573,  158,  347,  573,  573,
+      573,  573,  573,  573,  573,  573,  158,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  158,  573,  358,  358,
+      358,  358,  358,  358,  359,  359,  359,  360,  348,  348,
+      348,  348,  348,  348,  349,  349,  349,  350,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  421,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  426,  158,  573,
+      573,  573,  573,  573,  573,  573,  573,  431,  158,  573,
+      573,  573,  573,  573,  573,  573,  573,  368,  422,  422,
+      422,  422,  422,  422,  423,  423,  423,  424,  427,  427,
+      427,  427,  427,  427,  428,  428,  428,  429,  432,  432,
+      432,  432,  432,  432,  433,  433,  433,  434,  369,  369,
+      369,  369,  369,  369,  370,  370,  370,  371,  158,  436,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  441,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      437,  437,  437,  437,  437,  437,  438,  438,  438,  439,
+      442,  442,  442,  442,  442,  442,  443,  443,  443,  444,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  446,
+      573,  158,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  268,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  273,  573,  573,  573,  573,  573,  573,  573,  573,
+      447,  447,  447,  447,  447,  447,  448,  448,  448,  449,
+      573,  573,  269,  269,  269,  269,  269,  269,  270,  270,
+      270,  271,  274,  274,  274,  274,  274,  274,  275,  275,
+      275,  276,  278,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  158,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  158,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  158,  279,  279,  279,  279,  279,  279,  280,
+      280,  280,  281,  573,  389,  389,  389,  389,  389,  389,
+      389,  389,  389,  389,  389,  389,  389,  389,  389,  389,
+      389,  389,  389,  389,  389,  389,  389,  389,  389,  389,
+      389,  389,  573,  268,  158,  573,  573,  573,  573,  573,
+      573,  573,  573,  268,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  347,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  158,  269,  269,  269,  269,  269,  269,
+
+      270,  270,  270,  271,  269,  269,  269,  269,  269,  269,
+      270,  270,  270,  271,  348,  348,  348,  348,  348,  348,
+      349,  349,  349,  350,  573,  352,  393,  393,  393,  393,
+      393,  393,  393,  393,  393,  393,  393,  393,  393,  393,
+      393,  393,  393,  393,  393,  393,  393,  393,  393,  393,
+      393,  393,  393,  393,  357,  158,  353,  353,  353,  353,
+      353,  353,  354,  354,  354,  355,  158,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  158,  573,  573,  573,
+      573,  573,  573,  573,  573,  358,  358,  358,  358,  358,
+      358,  359,  359,  359,  360,  573,  158,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  362,  158,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  362,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  368,  158,  573,
+      573,  573,  573,  573,  573,  573,  573,  363,  363,  363,
+      363,  363,  363,  364,  364,  364,  365,  373,  363,  363,
+      363,  363,  363,  363,  364,  364,  364,  365,  369,  369,
+      369,  369,  369,  369,  370,  370,  370,  371,  378,  158,
+      573,  573,  573,  573,  573,  573,  573,  573,  374,  374,
+      374,  374,  374,  374,  375,  375,  375,  376,  158,  268,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  158,  379,
+      379,  379,  379,  379,  379,  380,  380,  380,  381,  573,
+      158,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      269,  269,  269,  269,  269,  269,  270,  270,  270,  271,
+      268,  573,  573,  573,  573,  573,  573,  573,  573,  158,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  347,
+      573,  158,  573,  573,  573,  573,  573,  573,  573,  352,
+      573,  269,  269,  269,  269,  269,  269,  270,  270,  270,
+      271,  357,  573,  573,  573,  573,  573,  573,  573,  573,
+      348,  348,  348,  348,  348,  348,  349,  349,  349,  350,
+
+      353,  353,  353,  353,  353,  353,  354,  354,  354,  355,
+      347,  158,  358,  358,  358,  358,  358,  358,  359,  359,
+      359,  360,  347,  158,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  158,  573,  573,  573,  573,  573,  573,
+      573,  348,  348,  348,  348,  348,  348,  349,  349,  349,
+      350,  573,  158,  348,  348,  348,  348,  348,  348,  349,
+      349,  349,  350,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  421,  573,  158,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  426,  573,  573,  573,  573,  573,
+      573,  573,  573,  158,  431,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  422,  422,  422,  422,  422,  422,  423,
+      423,  423,  424,  368,  573,  427,  427,  427,  427,  427,
+      427,  428,  428,  428,  429,  432,  432,  432,  432,  432,
+      432,  433,  433,  433,  434,  368,  158,  573,  573,  573,
+      573,  573,  573,  573,  369,  369,  369,  369,  369,  369,
+      370,  370,  370,  371,  436,  158,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  369,  369,  369,  369,
+      369,  369,  370,  370,  370,  371,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  437,  437,  437,  437,  437,
+      437,  438,  438,  438,  439,  573,  573,  441,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  446,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  442,  442,
+      442,  442,  442,  442,  443,  443,  443,  444,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  447,  447,  447,
+      447,  447,  447,  448,  448,  448,  449,   59,   59,   59,
+       59,   59,   59,   59,   59,   59,   59,   59,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   60,   60,   65,
+       65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+
+       69,   77,   77,   77,   77,   77,   77,   77,   77,   77,
+       77,   77,   79,   79,   79,   79,   79,   79,   79,   79,
+       86,   86,   86,   86,   86,   86,   86,   86,   91,   91,
+      158,  158,  158,  158,  158,  158,  158,  573,  158,  158,
+      158,   91,  573,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,  166,  573,  166,  166,  166,  166,  166,  166,
+      166,  166,  166,  167,  167,  167,  167,  167,  167,  167,
+      167,  167,  167,  167,  176,  573,  176,  176,  176,  176,
+      176,  176,  176,  176,  176,  177,  573,  177,  177,  177,
+      177,  177,  177,  177,  177,  177,  178,  178,  178,  178,
+
+      178,  178,  178,  178,  183,  573,  183,  183,  183,  183,
+      183,  183,  183,  183,  183,  184,  573,  184,  184,  184,
+      184,  184,  184,  184,  184,  184,  185,  185,  185,  185,
+      185,  185,  185,  185,  573,  573,  185,  190,  573,  190,
+      190,  190,  190,  190,  190,  190,  190,  190,  191,  573,
+      191,  191,  191,  191,  191,  191,  191,  191,  191,  192,
+      192,  192,  192,  192,  192,  192,  192,  573,  573,  192,
+      197,  573,  197,  197,  197,  197,  197,  197,  197,  197,
+      197,  198,  573,  198,  198,  198,  198,  198,  198,  198,
+      198,  198,   77,   77,   77,   77,   77,   77,   77,   77,
+
+       77,   77,   77,   79,   79,   79,   79,   79,   79,   79,
+       79,  200,  573,  200,  200,  200,  200,  200,  200,  200,
+      200,  200,  201,  573,  201,  201,  201,  201,  201,  201,
+      201,  201,  201,   86,  573,   86,   86,   86,   86,   86,
+       86,   86,   86,   86,  213,  573,  213,  213,  213,  213,
+      213,  213,  213,  213,  213,  214,  573,  214,  214,  214,
+      214,  214,  214,  214,  214,  214,   86,   86,   86,   86,
+       86,   86,   86,   86,   91,   91,   91,  573,   91,   91,
+       91,   91,   91,   91,   91,   91,   91,  166,  573,  166,
+      166,  166,  166,  166,  166,  166,  166,  166,  167,  167,
+
+      167,  167,  167,  167,  167,  167,  167,  167,  167,  176,
+      573,  176,  176,  176,  176,  176,  176,  176,  176,  176,
+      177,  573,  177,  177,  177,  177,  177,  177,  177,  177,
+      177,  240,  240,  573,  240,  240,  240,  240,  240,  240,
+      240,  240,  246,  246,  246,  573,  246,  246,  246,  246,
+      246,  246,  246,  158,  158,  158,  158,  158,  158,  158,
+      158,  158,  158,  158,  267,  267,  267,  267,  267,  267,
+      267,  267,  267,  267,  267,  272,  272,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  277,  277,  277,  277,
+      277,  277,  277,  277,  277,  277,  277,  293,  573,  293,
+
+      293,  293,  293,  293,  293,  293,  293,  293,  178,  178,
+      178,  178,  178,  178,  178,  178,  183,  573,  183,  183,
+      183,  183,  183,  183,  183,  183,  183,  184,  573,  184,
+      184,  184,  184,  184,  184,  184,  184,  184,  294,  573,
+      294,  294,  294,  294,  294,  294,  294,  294,  294,  185,
+      185,  185,  185,  185,  185,  185,  185,  573,  573,  185,
+      190,  573,  190,  190,  190,  190,  190,  190,  190,  190,
+      190,  191,  573,  191,  191,  191,  191,  191,  191,  191,
+      191,  191,  295,  573,  295,  295,  295,  295,  295,  295,
+      295,  295,  295,  192,  192,  192,  192,  192,  192,  192,
+
+      192,  573,  573,  192,  197,  573,  197,  197,  197,  197,
+      197,  197,  197,  197,  197,  198,  573,  198,  198,  198,
+      198,  198,  198,  198,  198,  198,  296,  573,  296,  296,
+      296,  296,  296,  296,  296,  296,  296,   79,  573,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,  297,  573,
+      297,  297,  297,  297,  297,  297,  297,  297,  297,  202,
+      573,  202,  202,  202,  202,  202,  202,  202,  202,  202,
+      298,  573,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  299,  299,  299,  299,  299,  299,  299,  299,  299,
+      299,  299,  308,  573,  308,  308,  308,  308,  308,  308,
+
+      308,  308,  308,  309,  573,  309,  309,  309,  309,  309,
+      309,  309,  309,  309,   86,  573,   86,   86,   86,   86,
+       86,   86,   86,   86,   86,  310,  573,  310,  310,  310,
+      310,  310,  310,  310,  310,  310,   91,   91,   91,   91,
+       91,   91,   91,   91,   91,  573,   91,  240,  240,  240,
+      240,  240,  240,  240,  240,  240,  240,  240,  158,  158,
+      158,  158,  158,  158,  158,  158,  158,  158,  158,  267,
+      267,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+
+      277,  277,  346,  346,  346,  346,  346,  346,  346,  346,
+      346,  346,  346,  351,  351,  351,  351,  351,  351,  351,
+      351,  351,  351,  351,  356,  356,  356,  356,  356,  356,
+      356,  356,  356,  356,  356,  361,  361,  361,  361,  361,
+      361,  361,  361,  361,  361,  361,  366,  573,  366,  366,
+      366,  366,  366,  366,  366,  366,  366,  367,  367,  367,
+      367,  367,  367,  367,  367,  367,  367,  367,  372,  372,
+      372,  372,  372,  372,  372,  372,  372,  372,  372,  377,
+      377,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+      178,  573,  178,  178,  178,  178,  178,  178,  178,  178,
+
+      178,  185,  573,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  192,  573,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,   79,  573,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,  202,  573,  202,  202,  202,  202,
+      202,  202,  202,  202,  202,  383,  573,  383,  383,  383,
+      383,  383,  383,  383,  383,  383,   86,  573,   86,   86,
+       86,   86,   86,   86,   86,   86,   86,  389,  389,  389,
+      389,  389,  389,  573,  389,  573,  573,  389,  393,  393,
+      393,  393,  393,  393,  573,  393,  573,  573,  393,  397,
+      397,  573,  397,  397,  397,  397,  397,  397,  397,  397,
+
+      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
+      158,  267,  267,  267,  267,  267,  267,  267,  267,  267,
+      267,  267,  272,  272,  272,  272,  272,  272,  272,  272,
+      272,  272,  272,  277,  277,  277,  277,  277,  277,  277,
+      277,  277,  277,  277,  346,  346,  346,  346,  346,  346,
+      346,  346,  346,  346,  346,  351,  351,  351,  351,  351,
+      351,  351,  351,  351,  351,  351,  356,  356,  356,  356,
+      356,  356,  356,  356,  356,  356,  356,  361,  361,  361,
+      361,  361,  361,  361,  361,  361,  361,  361,  367,  367,
+      367,  367,  367,  367,  367,  367,  367,  367,  367,  372,
+
+      372,  372,  372,  372,  372,  372,  372,  372,  372,  372,
+      377,  377,  377,  377,  377,  377,  377,  377,  377,  377,
+      377,  420,  420,  420,  420,  420,  420,  420,  420,  420,
+      420,  420,  425,  425,  425,  425,  425,  425,  425,  425,
+      425,  425,  425,  430,  430,  430,  430,  430,  430,  430,
+      430,  430,  430,  430,  435,  435,  435,  435,  435,  435,
+      435,  435,  435,  435,  435,  440,  440,  440,  440,  440,
+      440,  440,  440,  440,  440,  440,  445,  445,  445,  445,
+      445,  445,  445,  445,  445,  445,  445,  202,  573,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  389,  389,
+
+      389,  389,  389,  389,  389,  389,  573,  573,  389,  451,
+      573,  451,  451,  451,  451,  451,  451,  451,  451,  451,
+      452,  573,  452,  452,  452,  452,  452,  452,  452,  452,
+      452,  393,  393,  393,  393,  393,  393,  393,  393,  573,
+      573,  393,  454,  573,  454,  454,  454,  454,  454,  454,
+      454,  454,  454,  455,  573,  455,  455,  455,  455,  455,
+      455,  455,  455,  455,  397,  397,  397,  397,  397,  397,
+      397,  397,  397,  397,  397,  458,  458,  573,  458,  458,
+      458,  458,  458,  458,  458,  458,  158,  158,  158,  158,
+      158,  158,  158,  158,  158,  158,  158,  267,  267,  267,
+
+      267,  267,  267,  267,  267,  267,  267,  267,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  272,  272,  277,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      346,  346,  346,  346,  346,  346,  346,  346,  346,  346,
+      346,  351,  351,  351,  351,  351,  351,  351,  351,  351,
+      351,  351,  356,  356,  356,  356,  356,  356,  356,  356,
+      356,  356,  356,  361,  361,  361,  361,  361,  361,  361,
+      361,  361,  361,  361,  367,  367,  367,  367,  367,  367,
+      367,  367,  367,  367,  367,  372,  372,  372,  372,  372,
+      372,  372,  372,  372,  372,  372,  377,  377,  377,  377,
+
+      377,  377,  377,  377,  377,  377,  377,  420,  420,  420,
+      420,  420,  420,  420,  420,  420,  420,  420,  425,  425,
+      425,  425,  425,  425,  425,  425,  425,  425,  425,  430,
+      430,  430,  430,  430,  430,  430,  430,  430,  430,  430,
+      435,  435,  435,  435,  435,  435,  435,  435,  435,  435,
+      435,  440,  440,  440,  440,  440,  440,  440,  440,  440,
+      440,  440,  445,  445,  445,  445,  445,  445,  445,  445,
+      445,  445,  445,  389,  573,  389,  389,  389,  389,  389,
+      389,  389,  389,  389,  478,  573,  478,  478,  478,  478,
+      478,  478,  478,  478,  478,  393,  573,  393,  393,  393,
+
+      393,  393,  393,  393,  393,  393,  479,  573,  479,  479,
+      479,  479,  479,  479,  479,  479,  479,  480,  480,  573,
+      480,  480,  480,  480,  480,  480,  480,  480,  458,  458,
+      458,  458,  458,  458,  458,  458,  458,  458,  458,   15,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573
+    } ;
+
+static yyconst flex_int16_t yy_chk[4546] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    5,   17,   74,   22,   17,
+       74,  128,  225,  128,   33,  633,  225,   21,   22,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   33,
+       25,   35,   36,   25,  220,   40,  104,  106,   35,   41,
+       50,   26,   36,   37,   36,  106,   37,  106,  104,   26,
+      220,   26,   40,   26,   41,   94,  143,  143,  143,  204,
+       53,   37,   51,   97,   95,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+
+        5,    5,    5,    5,    6,   21,   21,   21,   21,   21,
+       21,   21,   21,   21,   21,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25,   26,  168,   50,   37,   37,
+       37,   37,   37,   37,   37,   37,   37,   37,   44,   51,
+       53,   95,   94,   97,  601,   44,  204,   44,   53,   44,
+       44,   97,   44,  571,   44,   44,   44,  144,  144,  144,
+      293,   44,  569,   44,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+
+        6,    6,    6,    9,   39,   43,   43,   43,   60,  541,
+       43,  227,   43,  567,  227,   39,  153,  168,   79,  145,
+      145,  145,  153,   39,  153,   39,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   65,  146,  146,  146,
+      541,  565,  148,  248,  248,  248,   43,   69,  148,  148,
+      205,  293,   39,   39,   39,  563,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,   10,  467,   60,   60,   60,   60,
+
+       60,   60,   60,   60,   60,   60,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   86,   65,   65,   65,
+       65,   65,   65,   65,   65,   65,   65,  205,   69,   69,
+       69,   69,   69,   69,   69,   69,   69,   69,   91,  171,
+      467,   91,  249,  249,  249,  562,  169,   10,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,   10,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,   10,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,   10,   10,   10,
+       10,   10,   10,   10,   10,   11,   90,   90,   90,   90,
+       90,   90,   90,   90,   90,   90,  216,  216,  207,  561,
+
+      174,   86,   86,   86,   86,   86,   86,   86,   86,   86,
+       86,  169,  169,  560,  171,  171,  173,  217,  217,  559,
+      221,  558,  216,   91,   91,   91,   91,   91,   91,   91,
+       91,   91,   91,  217,  221,  557,  221,  185,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   12,  158,  207,  174,
+      173,  174,  174,  173,  555,  173,  207,  192,  173,  300,
+      174,  174,  554,  219,  173,  219,  219,  332,  173,  173,
+
+      173,  173,  173,  553,  219,  551,  549,  332,  158,  158,
+      158,  158,  158,  158,  158,  158,  158,  158,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  301,   12,
+       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,   32,  192,  192,
+      192,  192,  192,  192,  192,  192,  192,  192,   32,   32,
+      300,   32,   32,  258,  202,  258,  328,  303,  548,  547,
+       32,   32,  546,  301,  301,   32,  258,  159,  328,  330,
+
+      545,  544,  539,  330,   32,  330,   32,  160,   32,  538,
+      330,   32,   32,  537,   32,  535,  534,   32,  161,   32,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   61,  159,  533,
+      532,  178,  303,  303,  329,  531,  530,  400,  160,  202,
+      202,  202,  202,  202,  202,  202,  202,  202,  202,  161,
+      329,  329,  329,  400,  400,  400,  306,  529,  528,  159,
+      159,  159,  159,  159,  159,  159,  159,  159,  159,  160,
+
+      160,  160,  160,  160,  160,  160,  160,  160,  160,  527,
+      161,  161,  161,  161,  161,  161,  161,  161,  161,  161,
+      526,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,   61,
+       66,  218,  267,  523,  218,  306,  218,  306,  306,  218,
+      521,  519,  268,  250,  518,  218,  306,  306,  517,  218,
+      218,  218,  218,  218,  516,  250,  515,  514,  218,  250,
+      250,  250,  269,  267,  267,  267,  267,  267,  267,  267,
+
+      267,  267,  267,  268,  268,  268,  268,  268,  268,  268,
+      268,  268,  268,  270,  322,  322,  322,  322,  322,  322,
+      322,  322,  322,  322,   66,   66,   66,   66,   66,   66,
+       66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
+       66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
+       66,   66,   70,  269,  271,  323,  323,  323,  323,  323,
+      323,  323,  323,  323,  323,  513,  512,  511,  510,  508,
+      506,  505,  504,  503,  270,  502,  500,  499,  497,  496,
+      495,  494,  493,  492,  269,  269,  269,  269,  269,  269,
+      269,  269,  269,  269,  305,  272,  491,  490,  488,  487,
+
+      486,  485,  401,  401,  401,  270,  270,  270,  270,  270,
+      270,  270,  270,  270,  270,  271,   70,   70,   70,   70,
+       70,   70,   70,   70,   70,   70,   70,   70,   70,   70,
+       70,   70,   70,   70,   70,   70,   70,   70,   70,   70,
+       70,   70,   70,   70,   81,  401,  271,  271,  271,  271,
+      271,  271,  271,  271,  271,  271,  272,  484,  305,  483,
+      482,  305,  480,  305,  477,  476,  305,  346,  475,  474,
+      473,  472,  305,  471,  470,  469,  305,  305,  305,  305,
+      305,  468,  466,  465,  464,  463,  462,  272,  272,  272,
+      272,  272,  272,  272,  272,  272,  272,  461,  346,  346,
+
+      346,  346,  346,  346,  346,  346,  346,  346,   81,   81,
+       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
+       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
+       81,   81,   81,   81,   81,   81,  274,  460,  458,  419,
+      418,  417,  416,  415,  414,  413,   81,  100,  100,  100,
+      100,  100,  100,  100,  100,  100,  100,  100,  100,  100,
+      100,  100,  100,  100,  100,  100,  100,  100,  100,  100,
+      100,  100,  100,  100,  100,  100,  100,  100,  100,  100,
+      100,  100,  100,  100,  180,  347,  412,  411,  410,  409,
+      408,  407,  406,  405,  404,  403,  402,  274,  398,  397,
+
+      382,  378,  373,  366,  362,  345,  344,  343,  342,  341,
+      339,  338,  337,  336,  335,  275,  347,  347,  347,  347,
+      347,  347,  347,  347,  347,  347,  333,  276,  274,  274,
+      274,  274,  274,  274,  274,  274,  274,  274,  277,  331,
+      327,  326,  320,  318,  315,  314,  312,  302,  180,  180,
+      180,  180,  180,  180,  180,  180,  180,  180,  180,  180,
+      180,  180,  180,  180,  180,  180,  180,  180,  180,  180,
+      180,  180,  180,  180,  180,  180,  275,  283,  273,  265,
+      264,  263,  262,  261,  260,  259,  180,  187,  276,  279,
+      257,  256,  255,  254,  253,  252,  245,  244,  243,  277,
+
+      240,  226,  224,  223,  222,  170,  162,  275,  275,  275,
+      275,  275,  275,  275,  275,  275,  275,  157,  156,  276,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  389,
+      277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+      280,  393,  155,  154,  152,  151,  150,  149,  147,  142,
+      279,  187,  187,  187,  187,  187,  187,  187,  187,  187,
+      187,  187,  187,  187,  187,  187,  187,  187,  187,  187,
+      187,  187,  187,  187,  187,  187,  187,  187,  187,  194,
+      139,  279,  279,  279,  279,  279,  279,  279,  279,  279,
+      279,  138,  137,  135,  134,  125,  124,  123,  121,  120,
+
+      116,  280,  115,  112,  111,  110,  109,  107,  105,  103,
+      389,  389,  389,  389,  389,  389,  389,  389,  389,  389,
+       77,   76,  393,  393,  393,  393,  393,  393,  393,  393,
+      393,  393,  280,  280,  280,  280,  280,  280,  280,  280,
+      280,  280,   75,  194,  194,  194,  194,  194,  194,  194,
+      194,  194,  194,  194,  194,  194,  194,  194,  194,  194,
+      194,  194,  194,  194,  194,  194,  194,  194,  194,  194,
+      194,  210,  210,  210,  210,  210,  210,  210,  210,  210,
+      210,  210,  210,  210,  210,  210,  210,  210,  210,  210,
+      210,  210,  210,  210,  210,  210,  210,  210,  210,  210,
+
+      210,  210,  210,  210,  210,  210,  210,  210,  281,  420,
+       47,   38,   31,   30,   20,   19,   18,   15,  348,  421,
+       14,   13,    8,    7,    0,    0,    0,    0,  349,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,  350,    0,
+      420,  420,  420,  420,  420,  420,  420,  420,  420,  420,
+      421,  421,  421,  421,  421,  421,  421,  421,  421,  421,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  281,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  348,
+      351,    0,    0,    0,    0,    0,    0,    0,    0,  349,
+      352,    0,    0,    0,    0,    0,    0,    0,    0,  350,
+
+      281,  281,  281,  281,  281,  281,  281,  281,  281,  281,
+      348,  348,  348,  348,  348,  348,  348,  348,  348,  348,
+      349,  349,  349,  349,  349,  349,  349,  349,  349,  349,
+      350,  350,  350,  350,  350,  350,  350,  350,  350,  350,
+      353,  351,    0,    0,    0,    0,    0,    0,    0,    0,
+      354,  352,    0,    0,    0,    0,    0,    0,    0,    0,
+      355,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+      356,    0,  351,  351,  351,  351,  351,  351,  351,  351,
+      351,  351,  352,  352,  352,  352,  352,  352,  352,  352,
+      352,  352,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,  353,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,  354,  357,    0,    0,    0,    0,    0,    0,    0,
+        0,  355,  358,    0,    0,    0,    0,    0,    0,    0,
+        0,  356,  353,  353,  353,  353,  353,  353,  353,  353,
+      353,  353,  354,  354,  354,  354,  354,  354,  354,  354,
+      354,  354,  355,  355,  355,  355,  355,  355,  355,  355,
+      355,  355,  356,  356,  356,  356,  356,  356,  356,  356,
+      356,  356,  359,  357,    0,    0,    0,    0,    0,    0,
+        0,    0,  360,  358,    0,    0,    0,    0,    0,    0,
+        0,    0,  361,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,  363,    0,  357,  357,  357,  357,  357,  357,
+      357,  357,  357,  357,  358,  358,  358,  358,  358,  358,
+      358,  358,  358,  358,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  359,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  360,  364,    0,    0,    0,    0,    0,
+        0,    0,    0,  361,  365,    0,    0,    0,    0,    0,
+        0,    0,    0,  363,  359,  359,  359,  359,  359,  359,
+      359,  359,  359,  359,  360,  360,  360,  360,  360,  360,
+      360,  360,  360,  360,  361,  361,  361,  361,  361,  361,
+      361,  361,  361,  361,  363,  363,  363,  363,  363,  363,
+
+      363,  363,  363,  363,  367,  364,    0,    0,    0,    0,
+        0,    0,    0,    0,  368,  365,    0,    0,    0,    0,
+        0,    0,    0,    0,  369,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,  370,    0,  364,  364,  364,  364,
+      364,  364,  364,  364,  364,  364,  365,  365,  365,  365,
+      365,  365,  365,  365,  365,  365,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,  367,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,  368,  371,    0,    0,    0,
+        0,    0,    0,    0,    0,  369,  372,    0,    0,    0,
+        0,    0,    0,    0,    0,  370,  367,  367,  367,  367,
+
+      367,  367,  367,  367,  367,  367,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  369,  369,  369,  369,
+      369,  369,  369,  369,  369,  369,  370,  370,  370,  370,
+      370,  370,  370,  370,  370,  370,  374,  371,    0,    0,
+        0,    0,    0,    0,    0,    0,  375,  372,    0,    0,
+        0,    0,    0,    0,    0,    0,  376,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  377,    0,  371,  371,
+      371,  371,  371,  371,  371,  371,  371,  371,  372,  372,
+      372,  372,  372,  372,  372,  372,  372,  372,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,  374,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,  375,  379,    0,
+        0,    0,    0,    0,    0,    0,    0,  376,  380,    0,
+        0,    0,    0,    0,    0,    0,    0,  377,  374,  374,
+      374,  374,  374,  374,  374,  374,  374,  374,  375,  375,
+      375,  375,  375,  375,  375,  375,  375,  375,  376,  376,
+      376,  376,  376,  376,  376,  376,  376,  376,  377,  377,
+      377,  377,  377,  377,  377,  377,  377,  377,  381,  379,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  380,
+      422,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+      423,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+
+      379,  379,  379,  379,  379,  379,  379,  379,  379,  379,
+      380,  380,  380,  380,  380,  380,  380,  380,  380,  380,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  381,
+        0,  424,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,  422,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,  423,    0,    0,    0,    0,    0,    0,    0,    0,
+      381,  381,  381,  381,  381,  381,  381,  381,  381,  381,
+      390,    0,  422,  422,  422,  422,  422,  422,  422,  422,
+      422,  422,  423,  423,  423,  423,  423,  423,  423,  423,
+      423,  423,  424,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,  425,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,  426,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,  427,  424,  424,  424,  424,  424,  424,  424,
+      424,  424,  424,    0,  390,  390,  390,  390,  390,  390,
+      390,  390,  390,  390,  390,  390,  390,  390,  390,  390,
+      390,  390,  390,  390,  390,  390,  390,  390,  390,  390,
+      390,  390,  394,  425,  428,    0,    0,    0,    0,    0,
+        0,    0,    0,  426,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  427,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  429,  425,  425,  425,  425,  425,  425,
+
+      425,  425,  425,  425,  426,  426,  426,  426,  426,  426,
+      426,  426,  426,  426,  427,  427,  427,  427,  427,  427,
+      427,  427,  427,  427,    0,  428,  394,  394,  394,  394,
+      394,  394,  394,  394,  394,  394,  394,  394,  394,  394,
+      394,  394,  394,  394,  394,  394,  394,  394,  394,  394,
+      394,  394,  394,  394,  429,  430,  428,  428,  428,  428,
+      428,  428,  428,  428,  428,  428,  431,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  432,    0,    0,    0,
+        0,    0,    0,    0,    0,  429,  429,  429,  429,  429,
+      429,  429,  429,  429,  429,    0,  433,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  430,  434,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,  431,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,  432,  435,    0,
+        0,    0,    0,    0,    0,    0,    0,  430,  430,  430,
+      430,  430,  430,  430,  430,  430,  430,  433,  431,  431,
+      431,  431,  431,  431,  431,  431,  431,  431,  432,  432,
+      432,  432,  432,  432,  432,  432,  432,  432,  434,  436,
+        0,    0,    0,    0,    0,    0,    0,    0,  433,  433,
+      433,  433,  433,  433,  433,  433,  433,  433,  437,  435,
+
+        0,    0,    0,    0,    0,    0,    0,    0,  438,  434,
+      434,  434,  434,  434,  434,  434,  434,  434,  434,    0,
+      439,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+      435,  435,  435,  435,  435,  435,  435,  435,  435,  435,
+      436,    0,    0,    0,    0,    0,    0,    0,    0,  440,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  437,
+        0,  441,    0,    0,    0,    0,    0,    0,    0,  438,
+        0,  436,  436,  436,  436,  436,  436,  436,  436,  436,
+      436,  439,    0,    0,    0,    0,    0,    0,    0,    0,
+      437,  437,  437,  437,  437,  437,  437,  437,  437,  437,
+
+      438,  438,  438,  438,  438,  438,  438,  438,  438,  438,
+      440,  442,  439,  439,  439,  439,  439,  439,  439,  439,
+      439,  439,  441,  443,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,  444,    0,    0,    0,    0,    0,    0,
+        0,  440,  440,  440,  440,  440,  440,  440,  440,  440,
+      440,    0,  445,  441,  441,  441,  441,  441,  441,  441,
+      441,  441,  441,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,  442,    0,  446,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,  443,    0,    0,    0,    0,    0,
+        0,    0,    0,  447,  444,    0,    0,    0,    0,    0,
+
+        0,    0,    0,  442,  442,  442,  442,  442,  442,  442,
+      442,  442,  442,  445,    0,  443,  443,  443,  443,  443,
+      443,  443,  443,  443,  443,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  446,  448,    0,    0,    0,
+        0,    0,    0,    0,  445,  445,  445,  445,  445,  445,
+      445,  445,  445,  445,  447,  449,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  446,  446,  446,  446,
+      446,  446,  446,  446,  446,  446,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,  447,  447,  447,  447,  447,
+      447,  447,  447,  447,  447,    0,    0,  448,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,  449,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,  448,  448,
+      448,  448,  448,  448,  448,  448,  448,  448,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,  449,  449,  449,
+      449,  449,  449,  449,  449,  449,  449,  574,  574,  574,
+      574,  574,  574,  574,  574,  574,  574,  574,  575,  575,
+      575,  575,  575,  575,  575,  575,  575,  575,  575,  576,
+      576,  576,  576,  576,  576,  576,  576,  576,  576,  576,
+      577,  577,  577,  577,  577,  577,  577,  577,  577,  577,
+
+      577,  578,  578,  578,  578,  578,  578,  578,  578,  578,
+      578,  578,  579,  579,  579,  579,  579,  579,  579,  579,
+      580,  580,  580,  580,  580,  580,  580,  580,  581,  581,
+      582,  582,  582,  582,  582,  582,  582,    0,  582,  582,
+      582,  583,    0,  583,  583,  583,  583,  583,  583,  583,
+      583,  583,  584,    0,  584,  584,  584,  584,  584,  584,
+      584,  584,  584,  585,  585,  585,  585,  585,  585,  585,
+      585,  585,  585,  585,  586,    0,  586,  586,  586,  586,
+      586,  586,  586,  586,  586,  587,    0,  587,  587,  587,
+      587,  587,  587,  587,  587,  587,  588,  588,  588,  588,
+
+      588,  588,  588,  588,  589,    0,  589,  589,  589,  589,
+      589,  589,  589,  589,  589,  590,    0,  590,  590,  590,
+      590,  590,  590,  590,  590,  590,  591,  591,  591,  591,
+      591,  591,  591,  591,    0,    0,  591,  592,    0,  592,
+      592,  592,  592,  592,  592,  592,  592,  592,  593,    0,
+      593,  593,  593,  593,  593,  593,  593,  593,  593,  594,
+      594,  594,  594,  594,  594,  594,  594,    0,    0,  594,
+      595,    0,  595,  595,  595,  595,  595,  595,  595,  595,
+      595,  596,    0,  596,  596,  596,  596,  596,  596,  596,
+      596,  596,  597,  597,  597,  597,  597,  597,  597,  597,
+
+      597,  597,  597,  598,  598,  598,  598,  598,  598,  598,
+      598,  599,    0,  599,  599,  599,  599,  599,  599,  599,
+      599,  599,  600,    0,  600,  600,  600,  600,  600,  600,
+      600,  600,  600,  602,    0,  602,  602,  602,  602,  602,
+      602,  602,  602,  602,  603,    0,  603,  603,  603,  603,
+      603,  603,  603,  603,  603,  604,    0,  604,  604,  604,
+      604,  604,  604,  604,  604,  604,  605,  605,  605,  605,
+      605,  605,  605,  605,  606,  606,  607,    0,  607,  607,
+      607,  607,  607,  607,  607,  607,  607,  608,    0,  608,
+      608,  608,  608,  608,  608,  608,  608,  608,  609,  609,
+
+      609,  609,  609,  609,  609,  609,  609,  609,  609,  610,
+        0,  610,  610,  610,  610,  610,  610,  610,  610,  610,
+      611,    0,  611,  611,  611,  611,  611,  611,  611,  611,
+      611,  612,  612,    0,  612,  612,  612,  612,  612,  612,
+      612,  612,  613,  613,  613,    0,  613,  613,  613,  613,
+      613,  613,  613,  614,  614,  614,  614,  614,  614,  614,
+      614,  614,  614,  614,  615,  615,  615,  615,  615,  615,
+      615,  615,  615,  615,  615,  616,  616,  616,  616,  616,
+      616,  616,  616,  616,  616,  616,  617,  617,  617,  617,
+      617,  617,  617,  617,  617,  617,  617,  618,    0,  618,
+
+      618,  618,  618,  618,  618,  618,  618,  618,  619,  619,
+      619,  619,  619,  619,  619,  619,  620,    0,  620,  620,
+      620,  620,  620,  620,  620,  620,  620,  621,    0,  621,
+      621,  621,  621,  621,  621,  621,  621,  621,  622,    0,
+      622,  622,  622,  622,  622,  622,  622,  622,  622,  623,
+      623,  623,  623,  623,  623,  623,  623,    0,    0,  623,
+      624,    0,  624,  624,  624,  624,  624,  624,  624,  624,
+      624,  625,    0,  625,  625,  625,  625,  625,  625,  625,
+      625,  625,  626,    0,  626,  626,  626,  626,  626,  626,
+      626,  626,  626,  627,  627,  627,  627,  627,  627,  627,
+
+      627,    0,    0,  627,  628,    0,  628,  628,  628,  628,
+      628,  628,  628,  628,  628,  629,    0,  629,  629,  629,
+      629,  629,  629,  629,  629,  629,  630,    0,  630,  630,
+      630,  630,  630,  630,  630,  630,  630,  631,    0,  631,
+      631,  631,  631,  631,  631,  631,  631,  631,  632,    0,
+      632,  632,  632,  632,  632,  632,  632,  632,  632,  634,
+        0,  634,  634,  634,  634,  634,  634,  634,  634,  634,
+      635,    0,  635,  635,  635,  635,  635,  635,  635,  635,
+      635,  636,  636,  636,  636,  636,  636,  636,  636,  636,
+      636,  636,  637,    0,  637,  637,  637,  637,  637,  637,
+
+      637,  637,  637,  638,    0,  638,  638,  638,  638,  638,
+      638,  638,  638,  638,  639,    0,  639,  639,  639,  639,
+      639,  639,  639,  639,  639,  640,    0,  640,  640,  640,
+      640,  640,  640,  640,  640,  640,  641,  641,  641,  641,
+      641,  641,  641,  641,  641,    0,  641,  642,  642,  642,
+      642,  642,  642,  642,  642,  642,  642,  642,  643,  643,
+      643,  643,  643,  643,  643,  643,  643,  643,  643,  644,
+      644,  644,  644,  644,  644,  644,  644,  644,  644,  644,
+      645,  645,  645,  645,  645,  645,  645,  645,  645,  645,
+      645,  646,  646,  646,  646,  646,  646,  646,  646,  646,
+
+      646,  646,  647,  647,  647,  647,  647,  647,  647,  647,
+      647,  647,  647,  648,  648,  648,  648,  648,  648,  648,
+      648,  648,  648,  648,  649,  649,  649,  649,  649,  649,
+      649,  649,  649,  649,  649,  650,  650,  650,  650,  650,
+      650,  650,  650,  650,  650,  650,  651,    0,  651,  651,
+      651,  651,  651,  651,  651,  651,  651,  652,  652,  652,
+      652,  652,  652,  652,  652,  652,  652,  652,  653,  653,
+      653,  653,  653,  653,  653,  653,  653,  653,  653,  654,
+      654,  654,  654,  654,  654,  654,  654,  654,  654,  654,
+      655,    0,  655,  655,  655,  655,  655,  655,  655,  655,
+
+      655,  656,    0,  656,  656,  656,  656,  656,  656,  656,
+      656,  656,  657,    0,  657,  657,  657,  657,  657,  657,
+      657,  657,  657,  658,    0,  658,  658,  658,  658,  658,
+      658,  658,  658,  658,  659,    0,  659,  659,  659,  659,
+      659,  659,  659,  659,  659,  660,    0,  660,  660,  660,
+      660,  660,  660,  660,  660,  660,  661,    0,  661,  661,
+      661,  661,  661,  661,  661,  661,  661,  662,  662,  662,
+      662,  662,  662,    0,  662,    0,    0,  662,  663,  663,
+      663,  663,  663,  663,    0,  663,    0,    0,  663,  664,
+      664,    0,  664,  664,  664,  664,  664,  664,  664,  664,
+
+      665,  665,  665,  665,  665,  665,  665,  665,  665,  665,
+      665,  666,  666,  666,  666,  666,  666,  666,  666,  666,
+      666,  666,  667,  667,  667,  667,  667,  667,  667,  667,
+      667,  667,  667,  668,  668,  668,  668,  668,  668,  668,
+      668,  668,  668,  668,  669,  669,  669,  669,  669,  669,
+      669,  669,  669,  669,  669,  670,  670,  670,  670,  670,
+      670,  670,  670,  670,  670,  670,  671,  671,  671,  671,
+      671,  671,  671,  671,  671,  671,  671,  672,  672,  672,
+      672,  672,  672,  672,  672,  672,  672,  672,  673,  673,
+      673,  673,  673,  673,  673,  673,  673,  673,  673,  674,
+
+      674,  674,  674,  674,  674,  674,  674,  674,  674,  674,
+      675,  675,  675,  675,  675,  675,  675,  675,  675,  675,
+      675,  676,  676,  676,  676,  676,  676,  676,  676,  676,
+      676,  676,  677,  677,  677,  677,  677,  677,  677,  677,
+      677,  677,  677,  678,  678,  678,  678,  678,  678,  678,
+      678,  678,  678,  678,  679,  679,  679,  679,  679,  679,
+      679,  679,  679,  679,  679,  680,  680,  680,  680,  680,
+      680,  680,  680,  680,  680,  680,  681,  681,  681,  681,
+      681,  681,  681,  681,  681,  681,  681,  682,    0,  682,
+      682,  682,  682,  682,  682,  682,  682,  682,  683,  683,
+
+      683,  683,  683,  683,  683,  683,    0,    0,  683,  684,
+        0,  684,  684,  684,  684,  684,  684,  684,  684,  684,
+      685,    0,  685,  685,  685,  685,  685,  685,  685,  685,
+      685,  686,  686,  686,  686,  686,  686,  686,  686,    0,
+        0,  686,  687,    0,  687,  687,  687,  687,  687,  687,
+      687,  687,  687,  688,    0,  688,  688,  688,  688,  688,
+      688,  688,  688,  688,  689,  689,  689,  689,  689,  689,
+      689,  689,  689,  689,  689,  690,  690,    0,  690,  690,
+      690,  690,  690,  690,  690,  690,  691,  691,  691,  691,
+      691,  691,  691,  691,  691,  691,  691,  692,  692,  692,
+
+      692,  692,  692,  692,  692,  692,  692,  692,  693,  693,
+      693,  693,  693,  693,  693,  693,  693,  693,  693,  694,
+      694,  694,  694,  694,  694,  694,  694,  694,  694,  694,
+      695,  695,  695,  695,  695,  695,  695,  695,  695,  695,
+      695,  696,  696,  696,  696,  696,  696,  696,  696,  696,
+      696,  696,  697,  697,  697,  697,  697,  697,  697,  697,
+      697,  697,  697,  698,  698,  698,  698,  698,  698,  698,
+      698,  698,  698,  698,  699,  699,  699,  699,  699,  699,
+      699,  699,  699,  699,  699,  700,  700,  700,  700,  700,
+      700,  700,  700,  700,  700,  700,  701,  701,  701,  701,
+
+      701,  701,  701,  701,  701,  701,  701,  702,  702,  702,
+      702,  702,  702,  702,  702,  702,  702,  702,  703,  703,
+      703,  703,  703,  703,  703,  703,  703,  703,  703,  704,
+      704,  704,  704,  704,  704,  704,  704,  704,  704,  704,
+      705,  705,  705,  705,  705,  705,  705,  705,  705,  705,
+      705,  706,  706,  706,  706,  706,  706,  706,  706,  706,
+      706,  706,  707,  707,  707,  707,  707,  707,  707,  707,
+      707,  707,  707,  708,    0,  708,  708,  708,  708,  708,
+      708,  708,  708,  708,  709,    0,  709,  709,  709,  709,
+      709,  709,  709,  709,  709,  710,    0,  710,  710,  710,
+
+      710,  710,  710,  710,  710,  710,  711,    0,  711,  711,
+      711,  711,  711,  711,  711,  711,  711,  712,  712,    0,
+      712,  712,  712,  712,  712,  712,  712,  712,  713,  713,
+      713,  713,  713,  713,  713,  713,  713,  713,  713,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573,  573,  573,  573,  573,  573,
+      573,  573,  573,  573,  573
+    } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[130] =
+    {   0,
+1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 1, 1, 0, 0, 0,     };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "regex.l"
+/*   Foma: a finite-state toolkit and library.                                 */
+/*   Copyright © 2008-2015 Mans Hulden                                         */
+/*   This file is part of foma.                                                */
+/*   Licensed under the Apache License, Version 2.0 (the "License");           */
+/*   you may not use this file except in compliance with the License.          */
+/*   You may obtain a copy of the License at                                   */
+/*      http://www.apache.org/licenses/LICENSE-2.0                             */
+/*   Unless required by applicable law or agreed to in writing, software       */
+/*   distributed under the License is distributed on an "AS IS" BASIS,         */
+/*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
+/*   See the License for the specific language governing permissions and       */
+/*   limitations under the License.                                            */
+#define YY_NO_INPUT 1
+#line 23 "regex.l"
+#include <stdio.h>
+#include "foma.h"
+#include "regex.h"
+
+struct defs {
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+};
+
+#define YY_EXTRA_TYPE struct defs *
+
+#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = yycolumn; yylloc->last_column = yycolumn+yyleng-1; yycolumn += yyleng;
+
+#define MAX_PARSE_DEPTH 100
+
+struct parser_vars {
+  int rewrite;
+  int rule_direction;
+  struct fsmcontexts *contexts;
+  struct fsmrules *rules;
+  struct rewrite_set *rewrite_rules;
+  char   *ystring;
+  struct fsm *ynet;
+  int ytype;
+};
+
+struct parser_vars parservarstack[MAX_PARSE_DEPTH];
+int g_parse_depth = 0;
+
+extern int yyparse(void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs); // TESTING...
+//extern int yyparse();
+extern int get_iface_lineno(void);
+extern int rewrite, rule_direction, substituting;
+extern struct fsmcontexts *contexts;
+extern struct fsmrules *rules;
+extern struct rewrite_set *rewrite_rules;
+extern struct fsm *current_parse;
+
+char *yyget_text(yyscan_t yyscanner);
+char *tempstr, *tempstr2;
+int yylex_init (yyscan_t* scanner);
+int yylex_init_extra (struct defs *defptr, yyscan_t *scanner);
+int yylex_destroy (yyscan_t scanner);
+int my_yyparse(char *my_string, int lineno, struct defined_networks *defined_nets, struct defined_functions *defined_funcs);
+
+int yywrap(yyscan_t scanner) {return 1; }
+
+int yyerror(YYLTYPE* yylloc, yyscan_t scanner, char *msg) {
+   if(yylloc->first_line)
+       fprintf(stderr, "%d.%d-%d.%d: error: ", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column);
+   fprintf(stderr, "%s%s at '%s'.\n", "***", msg, yyget_text(scanner));
+   return 1;
+}
+
+struct fsm *fsm_parse_regex(char *regex, struct defined_networks *defined_nets, struct defined_functions *defined_funcs) {
+    char *newregex;
+    current_parse = NULL;
+    newregex = (char*)xxmalloc(sizeof(char)*(strlen(regex)+2));
+    strcpy(newregex, regex);
+    strcat(newregex, ";");
+    if (my_yyparse(newregex, 1, defined_nets, defined_funcs) == 0) {
+	xxfree(newregex);
+	return(fsm_minimize(current_parse));
+    } else {
+	xxfree(newregex);
+	return(NULL);
+    }
+}
+
+/* Only used when reading regex from file */
+struct fsm *fsm_parse_regex_string(char *regex) {
+    current_parse = NULL;
+    if (my_yyparse(regex,1,g_defines,g_defines_f) == 0) {
+	xxfree(regex);
+	return(fsm_minimize(current_parse));
+    } else {
+	xxfree(regex);
+	return(NULL);
+    }
+}
+
+void yyset_lineno(int line_number,yyscan_t yyscanner);
+
+int my_yyparse(char *my_string, int lineno, struct defined_networks *defined_nets, struct defined_functions *defined_funcs) {
+    int yyp;
+    yyscan_t scanner;
+    struct defs defsptr[1];
+    YY_BUFFER_STATE my_string_buffer;
+
+    defsptr->defined_nets = defined_nets;
+    defsptr->defined_funcs = defined_funcs;
+    yylex_init_extra(defsptr,&scanner);
+
+    my_string_buffer = yy_scan_string(my_string,scanner);
+    yyset_lineno(lineno,scanner);
+    if (g_parse_depth > 0) {
+	if (g_parse_depth >= MAX_PARSE_DEPTH) {
+	    fprintf(stderr,"Exceeded parser stack depth.  Self-recursive call?\n");
+	    return 1;
+	}
+	/* Save variables on stack */
+	parservarstack[g_parse_depth].rewrite = rewrite;
+	parservarstack[g_parse_depth].rule_direction = rule_direction;
+	parservarstack[g_parse_depth].contexts = contexts;
+	parservarstack[g_parse_depth].rules = rules;
+	parservarstack[g_parse_depth].rewrite_rules = rewrite_rules;
+    }
+    g_parse_depth++;
+    yyp = yyparse(scanner, defined_nets, defined_funcs);
+    g_parse_depth--;
+    if (g_parse_depth > 0) {
+	/* Restore parse variables */
+	rewrite        = parservarstack[g_parse_depth].rewrite;
+	rule_direction = parservarstack[g_parse_depth].rule_direction;
+	contexts       = parservarstack[g_parse_depth].contexts;
+	rules          = parservarstack[g_parse_depth].rules;
+	rewrite_rules  = parservarstack[g_parse_depth].rewrite_rules;
+    }
+    yy_delete_buffer(my_string_buffer,scanner);
+    yylex_destroy(scanner);
+    return yyp;
+}
+
+/* Reserved multicharacter symbols are a little tricky to define */
+/* what we're doing is excluding some combinations of multibyte sequences */
+/* using the {-} construct in flex */
+
+#line 1826 "lex.yy.c"
+
+#define INITIAL 0
+#define DEFI 1
+#define QTD 2
+#define QTDEND 3
+#define UQ 4
+#define EQ 5
+#define ENDQ 6
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    int yy_n_chars;
+    int yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    YYSTYPE * yylval_r;
+
+    YYLTYPE * yylloc_r;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+    /* This must go here because YYSTYPE and YYLTYPE are included
+     * from bison output in section 1.*/
+    #    define yylval yyg->yylval_r
+    
+    #    define yylloc yyg->yylloc_r
+    
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (yyscan_t yyscanner );
+
+int yyget_debug (yyscan_t yyscanner );
+
+void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *yyget_in (yyscan_t yyscanner );
+
+void yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *yyget_out (yyscan_t yyscanner );
+
+void yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+int yyget_leng (yyscan_t yyscanner );
+
+char *yyget_text (yyscan_t yyscanner );
+
+int yyget_lineno (yyscan_t yyscanner );
+
+void yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner );
+
+void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+       YYLTYPE *yyget_lloc (yyscan_t yyscanner );
+    
+        void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+    
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+/*extern "C"*/ int yywrap (yyscan_t yyscanner ); // TESTING...
+#else
+extern int yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  ,yyscan_t yyscanner);
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex							\
+               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 156 "regex.l"
+
+
+ /* we're matching braced strings */
+
+#line 2083 "lex.yy.c"
+
+    yylval = yylval_param;
+
+    yylloc = yylloc_param;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+		}
+
+		yy_load_buffer_state(yyscanner );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 574 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 4440 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+			{
+			int yyl;
+			for ( yyl = 0; yyl < yyleng; ++yyl )
+				if ( yytext[yyl] == '\n' )
+					   
+    do{ yylineno++;
+        yycolumn=0;
+    }while(0)
+;
+			}
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 160 "regex.l"
+{
+    yylval_param->net = fsm_explode(yytext);
+    return NET;
+}
+	YY_BREAK
+/* Read binary file */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 166 "regex.l"
+{
+    tempstr = xxstrndup(yytext+2,yyleng-3);
+    yylval_param->net = fsm_read_binary_file(tempstr);
+    xxfree(tempstr);
+    if (yylval_param->net != NULL) {
+	return NET;
+    }
+}
+	YY_BREAK
+/* Read regex from file */
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 176 "regex.l"
+{
+    tempstr = xxstrndup(yytext+4,yyleng-5);
+    tempstr2 = file_to_mem(tempstr);
+    xxfree(tempstr);
+    if (tempstr2 != NULL) {
+	yylval_param->net = fsm_parse_regex_string(tempstr2);
+	if (yylval_param->net != NULL) {
+	    return NET;
+	}  
+    }
+}
+	YY_BREAK
+/* Read text file */
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 189 "regex.l"
+{
+    tempstr = xxstrndup(yytext+5,yyleng-6);
+    yylval_param->net = fsm_read_text_file(tempstr);
+    xxfree(tempstr);
+    if (yylval_param->net != NULL) {
+	return NET;
+    }
+}
+	YY_BREAK
+/* Read spaced text file */
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+#line 199 "regex.l"
+{
+    tempstr = xxstrndup(yytext+6,yyleng-7);
+    yylval_param->net = fsm_read_spaced_text_file(tempstr);
+    xxfree(tempstr);
+    if (yylval_param->net != NULL) {
+	return NET;
+    }
+}
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 208 "regex.l"
+{
+    //yylval_param->string = xxstrdup(yytext+1);
+    yylval_param->string = yytext+1;
+    return NCONCAT;
+}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 214 "regex.l"
+{
+    //yylval_param->string = xxstrdup(yytext+2);
+    yylval_param->string = yytext+2;
+    return MNCONCAT;
+}
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 219 "regex.l"
+{
+    yylval_param->string = yytext+2;
+//  yylval_param->string = xxstrdup(yytext+2);
+    return MORENCONCAT;
+}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 224 "regex.l"
+{
+    //  yylval_param->string = xxstrdup(yytext+2);
+    yylval_param->string = yytext+2;
+    return LESSNCONCAT;
+}
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 230 "regex.l"
+{
+
+}
+	YY_BREAK
+/* Start of universal quantifier */
+case 11:
+/* rule 11 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 235 "regex.l"
+{
+    BEGIN(UQ);
+}
+	YY_BREAK
+/* Start of existential quantifier */
+case 12:
+/* rule 12 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 240 "regex.l"
+{
+    BEGIN(EQ);
+}
+	YY_BREAK
+case 13:
+/* rule 13 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 245 "regex.l"
+{
+ /* Add quantifier to quantifier symbol table */
+
+ //yylval_param->string = xxstrdup(yytext);
+    yylval_param->string = yytext;
+    add_quantifier(yytext);
+    BEGIN(ENDQ);
+    return(UQUANT);
+}
+	YY_BREAK
+case 14:
+/* rule 14 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 255 "regex.l"
+{
+    /* Add quantifier to quantifier symbol table */
+    //yylval_param->string = xxstrdup(yytext);
+    yylval_param->string = yytext;
+    add_quantifier(yytext);
+    BEGIN(ENDQ);
+    return(EQUANT);
+}
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 264 "regex.l"
+{BEGIN(INITIAL);}
+	YY_BREAK
+/* Start of a quoted sequence of symbols */
+case 16:
+/* rule 16 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 267 "regex.l"
+{
+    BEGIN(QTD);
+}
+	YY_BREAK
+/* Stuff that goes inside " ", including UTF8 \uHHHH sequences */
+case 17:
+/* rule 17 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 272 "regex.l"
+{
+    decode_quoted(yytext);										  
+    yylval_param->net = fsm_symbol(yytext);
+    BEGIN(QTDEND);
+    return NET;
+}
+	YY_BREAK
+/* Disregard end quote */
+case 18:
+YY_RULE_SETUP
+#line 280 "regex.l"
+{ BEGIN(INITIAL);}
+	YY_BREAK
+/* Different epsilon variants: "" or [] or \epsilon */
+case 19:
+YY_RULE_SETUP
+#line 283 "regex.l"
+{
+  yylval_param->net = fsm_empty_string();
+  return NET;
+}
+	YY_BREAK
+/* The empty set */
+case 20:
+YY_RULE_SETUP
+#line 288 "regex.l"
+{
+   yylval_param->net = fsm_empty_set();
+   return NET;
+}
+	YY_BREAK
+/* Sigma */
+case 21:
+YY_RULE_SETUP
+#line 294 "regex.l"
+{
+  yylval_param->net = fsm_identity();  
+  return NET;
+}
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 299 "regex.l"
+{ return SUCCESSOR_OF; }
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 301 "regex.l"
+{ return ISUNAMBIGUOUS;   }
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 302 "regex.l"
+{ return ISIDENTITY;      } 
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 303 "regex.l"
+{ return ISFUNCTIONAL;    }
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 304 "regex.l"
+{ return NOTID;           }
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 305 "regex.l"
+{ return LETTERMACHINE;   }
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 306 "regex.l"
+{ return LOWERUNIQ;       }
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 307 "regex.l"
+{ return LOWERUNIQEPS;    }
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 308 "regex.l"
+{ return ALLFINAL;        }
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 309 "regex.l"
+{ return UNAMBIGUOUSPART; }
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 310 "regex.l"
+{ return AMBIGUOUSPART;   }
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 311 "regex.l"
+{ return AMBIGUOUSDOMAIN; }
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 312 "regex.l"
+{ return EQSUBSTRINGS;    }
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 313 "regex.l"
+{ return MARKFSMTAIL;     }
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 314 "regex.l"
+{ return MARKFSMTAILLOOP; }
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 315 "regex.l"
+{ return MARKFSMMIDLOOP;  }
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 316 "regex.l"
+{ return MARKFSMLOOP;     }
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 317 "regex.l"
+{ return ADDSINK;         }
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 318 "regex.l"
+{ return LEFTREWR;        }
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 319 "regex.l"
+{ return FLATTEN;         }
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 320 "regex.l"
+{ return SUBLABEL;        }
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 321 "regex.l"
+{ return CLOSESIGMA;      }
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 322 "regex.l"
+{ return CLOSESIGMAUNK;   }
+	YY_BREAK
+case 45:
+/* rule 45 can match eol */
+YY_RULE_SETUP
+#line 324 "regex.l"
+{
+   yylval_param->string = xxstrdup(yytext);
+   //yylval_param->string = yytext;
+   return FUNCTION;
+}
+	YY_BREAK
+/* The set of nonreserved symbols, or % followed by any UTF8 character */
+case 46:
+/* rule 46 can match eol */
+YY_RULE_SETUP
+#line 332 "regex.l"
+{
+  int i,j, skip, escaped;
+  if ((strncmp(yytext,"=",1) == 0) && (count_quantifiers() > 0)) {
+   int i;
+   /* Copy yytext because unput() trashes yytext */
+   char *yycopy = xxstrdup(yytext);
+   for ( i = yyleng - 1; i > 0; --i )
+     unput( yycopy[i] );
+   xxfree(yycopy);
+   return EQUALS;
+  }
+
+  for (escaped=0, i=0,j=0;*(yytext+i);) {
+    *(yytext+j) = *(yytext+i);
+    if (*(yytext+i) == '%') /* Skip escaping percent sign */ {
+      i++;
+      escaped++;
+    }
+    for(skip = utf8skip(yytext+i)+1; skip > 0; skip--) {
+	*(yytext+j) = *(yytext+i);
+        i++; j++;
+    }
+  }
+  *(yytext+j) = *(yytext+i);
+  if (substituting) {
+    yylval_param->string = xxstrdup(yytext);
+    //yylval_param->string = yytext;
+    return SUBVAL;
+  }
+  //  yylval_param->string = xxstrdup(yytext);
+  yylval_param->string = yytext;
+  if(find_defined(yyextra->defined_nets, yytext) != NULL) {
+    yylval_param->net = fsm_copy(find_defined(yyextra->defined_nets, yytext));
+  } else if (find_quantifier(yytext) != NULL) {
+      return VAR;
+  } else {
+    if (!escaped && strcmp(yytext, "0") == 0)
+      yylval_param->net = fsm_empty_string();
+    else if (!escaped && strcmp(yytext, "?") == 0)
+      yylval_param->net = fsm_identity();
+    else
+      yylval_param->net = fsm_symbol(yytext);
+  }
+  return NET;
+}
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 378 "regex.l"
+{ yylval_param->net = fsm_symbol(".#."); return NET;    }
+	YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 379 "regex.l"
+{ return CONTEXT;             }
+	YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 380 "regex.l"
+{ return XUPPER;              }
+	YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 381 "regex.l"
+{ return XLOWER;              }
+	YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 382 "regex.l"
+{ return FLAG_ELIMINATE;      }
+	YY_BREAK
+case 52:
+/* rule 52 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 383 "regex.l"
+{ return LDOT;                }
+	YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 384 "regex.l"
+{ return RDOT;                }
+	YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 385 "regex.l"
+{ return IMPLIES;             }
+	YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 386 "regex.l"
+{ return BICOND;              }
+	YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 387 "regex.l"
+{ return IN;                  }
+	YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 388 "regex.l"
+{ return COMPLEMENT;          }
+	YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 389 "regex.l"
+{ return COMPOSE;             }
+	YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 390 "regex.l"
+{ return LENIENT_COMPOSE;     }
+	YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 391 "regex.l"
+{ return PRIORITY_UNION_U;    }
+	YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 392 "regex.l"
+{ return PRIORITY_UNION_L;    }
+	YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 393 "regex.l"
+{ return SHUFFLE;             }
+	YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 394 "regex.l"
+{ return PRECEDES;            }
+	YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 395 "regex.l"
+{ return FOLLOWS;             }
+	YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 396 "regex.l"
+{ return TRIPLE_DOT;          }
+	YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 397 "regex.l"
+{                     yylval_param->type = ARROW_RIGHT; return ARROW;}
+	YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 398 "regex.l"
+{                 yylval_param->type = ARROW_RIGHT | ARROW_OPTIONAL; return ARROW;}
+	YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 399 "regex.l"
+{                     yylval_param->type = ARROW_LEFT; return ARROW;}
+	YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 400 "regex.l"
+{                 yylval_param->type = ARROW_LEFT | ARROW_OPTIONAL; return ARROW;}
+	YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 401 "regex.l"
+{                   yylval_param->type = ARROW_LEFT|ARROW_RIGHT; return ARROW;}
+	YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 402 "regex.l"
+{               yylval_param->type = ARROW_LEFT|ARROW_RIGHT|ARROW_OPTIONAL; return ARROW;}
+	YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 403 "regex.l"
+{ yylval_param->type = ARROW_RIGHT|ARROW_LONGEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 404 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_RIGHT|ARROW_LONGEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 405 "regex.l"
+{ yylval_param->type = ARROW_RIGHT|ARROW_SHORTEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 406 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_RIGHT|ARROW_SHORTEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 407 "regex.l"
+{ yylval_param->type = ARROW_RIGHT|ARROW_LONGEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 408 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_RIGHT|ARROW_LONGEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 409 "regex.l"
+{ yylval_param->type = ARROW_RIGHT|ARROW_SHORTEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 410 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_RIGHT|ARROW_SHORTEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 411 "regex.l"
+{ yylval_param->type = ARROW_LEFT|ARROW_LONGEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 412 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_LEFT|ARROW_LONGEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 413 "regex.l"
+{ yylval_param->type = ARROW_LEFT|ARROW_SHORTEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 414 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_LEFT|ARROW_SHORTEST_MATCH|ARROW_LEFT_TO_RIGHT; return ARROW;}
+	YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 415 "regex.l"
+{ yylval_param->type = ARROW_LEFT|ARROW_LONGEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 416 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_LEFT|ARROW_LONGEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 417 "regex.l"
+{ yylval_param->type = ARROW_LEFT|ARROW_SHORTEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 418 "regex.l"
+{ yylval_param->type = ARROW_OPTIONAL|ARROW_RIGHT|ARROW_SHORTEST_MATCH|ARROW_RIGHT_TO_LEFT; return ARROW;}
+	YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 420 "regex.l"
+{                     return CRESTRICT;           }
+	YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 421 "regex.l"
+{                   return SUBSTITUTE;          }
+	YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 422 "regex.l"
+{                     yylval_param->type = OP_UPWARD_REPLACE;    return DIRECTION; }
+	YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 423 "regex.l"
+{                     yylval_param->type = OP_RIGHTWARD_REPLACE; return DIRECTION; }
+	YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 424 "regex.l"
+{                     yylval_param->type = OP_LEFTWARD_REPLACE;  return DIRECTION; }
+	YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 425 "regex.l"
+{                     yylval_param->type = OP_DOWNWARD_REPLACE;  return DIRECTION; }
+	YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 426 "regex.l"
+{                   yylval_param->type = OP_TWO_LEVEL_REPLACE; return DIRECTION; }
+	YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 427 "regex.l"
+{                        return HIGH_CROSS_PRODUCT;  }
+	YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 428 "regex.l"
+{       return CROSS_PRODUCT;       }
+	YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 429 "regex.l"
+{                        return COMMA;               }
+	YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 430 "regex.l"
+{                       return DOUBLE_COMMA;        }
+	YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 431 "regex.l"
+{                   return IGNORE_INTERNAL;     }
+	YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 432 "regex.l"
+{                       return IGNORE_ALL;          }
+	YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 433 "regex.l"
+{                   return RIGHT_QUOTIENT;      }
+	YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 434 "regex.l"
+{                   return LEFT_QUOTIENT;       }
+	YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 435 "regex.l"
+{                   return INTERLEAVE_QUOTIENT; }
+	YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 436 "regex.l"
+{                       return TERM_NEGATION;       }
+	YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 437 "regex.l"
+{                       return MINUS;               }
+	YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 438 "regex.l"
+{                     return CONTAINS_OPT_ONE;    }
+	YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 439 "regex.l"
+{                     return CONTAINS_ONE;        }
+	YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 440 "regex.l"
+{                       return CONTAINS;            }
+	YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 441 "regex.l"
+{                       return KLEENE_PLUS;         }
+	YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 442 "regex.l"
+{                       return KLEENE_STAR;         }
+	YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 443 "regex.l"
+{ return INVERSE;     }
+	YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 444 "regex.l"
+{                      return REVERSE;             }
+	YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 445 "regex.l"
+{                       return LBRACKET;            }
+	YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 446 "regex.l"
+{                       return RBRACKET;            }
+	YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 447 "regex.l"
+{         return PRECEDES;            }
+	YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 448 "regex.l"
+{         return FOLLOWS;             }
+	YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 449 "regex.l"
+{         return NEQ;                 }
+	YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 450 "regex.l"
+{                       return LPAREN;              }
+	YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 451 "regex.l"
+{                       return RPAREN;              }
+	YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 452 "regex.l"
+{                       return ENDM;                } 
+	YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 453 "regex.l"
+{                       return ENDD;                }
+	YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 454 "regex.l"
+{                       return END;                 }
+	YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 455 "regex.l"
+{ return UNION;     }
+	YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 456 "regex.l"
+{ return INTERSECT; }
+	YY_BREAK
+case 125:
+/* rule 125 can match eol */
+YY_RULE_SETUP
+#line 458 "regex.l"
+{ yycolumn = 1; }
+	YY_BREAK
+case 126:
+/* rule 126 can match eol */
+YY_RULE_SETUP
+#line 459 "regex.l"
+{  }
+	YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 460 "regex.l"
+{  }
+	YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 461 "regex.l"
+{ }
+	YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 462 "regex.l"
+ECHO;
+	YY_BREAK
+#line 3012 "lex.yy.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(DEFI):
+case YY_STATE_EOF(QTD):
+case YY_STATE_EOF(QTDEND):
+case YY_STATE_EOF(UQ):
+case YY_STATE_EOF(EQ):
+case YY_STATE_EOF(ENDQ):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap(yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = yyg->yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, (size_t) num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin  ,yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 105);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 574 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	register char *yy_cp = yyg->yy_c_buf_p;
+
+	register YY_CHAR yy_c = 105;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 574 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 573);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+{
+	register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    yy_cp = yyg->yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yyg->yy_hold_char;
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yyg->yy_n_chars + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+    if ( c == '\n' ){
+        --yylineno;
+    }
+
+	yyg->yytext_ptr = yy_bp;
+	yyg->yy_hold_char = *yy_cp;
+	yyg->yy_c_buf_p = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart(yyin ,yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap(yyscanner ) )
+						return EOF;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	if ( c == '\n' )
+		   
+    do{ yylineno++;
+        yycolumn=0;
+    }while(0)
+;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+	}
+
+	yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+	yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
+     */
+	yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	yy_load_buffer_state(yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b,file ,yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+	yyfree((void *) b ,yyscanner );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+    
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_flush_buffer(b ,yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state(yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		yy_load_buffer_state(yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	int num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+								  
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b ,yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+	return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) yyalloc(n ,yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf,n ,yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * yyget_lval  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylval;
+}
+
+void yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylval = yylval_param;
+}
+
+YYLTYPE *yyget_lloc  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yylloc;
+}
+    
+void yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yylloc = yylloc_param;
+}
+    
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+
+int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+	
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+	
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 462 "regex.l"
diff --git a/back-ends/foma/cpp-version/lexcread.cc b/back-ends/foma/cpp-version/lexcread.cc
new file mode 100644
index 0000000..6e28849
--- /dev/null
+++ b/back-ends/foma/cpp-version/lexcread.cc
@@ -0,0 +1,1154 @@
+/*     Foma: a finite-state toolkit and library.  */
+/*     Copyright © 2008-2014 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "foma.h"
+#include "lexc.h"
+
+#define SIGMA_HASH_TABLESIZE 3079
+
+#define WORD_ENTRY 1
+#define REGEX_ENTRY 2
+
+#ifndef ORIGINAL
+extern int verbose_lexc_;
+#endif
+
+extern int g_lexc_align;
+
+struct multichar_symbols {
+    char *symbol;
+    short sigma_number;
+    struct multichar_symbols *next;
+};
+
+struct lexstates {             /* Separate list of LEXICON states */
+    char *name;
+    struct states *state;
+    struct lexstates *next;
+    unsigned char targeted;
+    unsigned char has_outgoing;
+};
+
+struct states {
+    struct trans {
+        short in;
+        short out;
+        struct states *target;
+        struct trans *next;
+    } *trans;
+    struct lexstates *lexstate; /* ptr to lexicon state */
+    int number;                 /* State number (generated later) */
+    unsigned int hashval;       /* Hash for remaining symbols until next lexstate */
+    unsigned char mergeable;    /* Can this state be merged with other suffix */
+                                /* 0 = NO, 1 = YES, 2 = DELETED/MERGED */
+    unsigned short distance;      /* Number of remaining symbols until lexstate */
+    struct states *merge_with;
+};
+
+struct statelist {
+    struct states *state;
+    struct statelist *next;
+    char start;
+    char final;
+};
+
+struct lexc_hashtable {      /* Hash for looking up symbols in sigma quickly */
+    char *symbol;
+    struct lexc_hashtable *next;
+    int sigma_number;
+};
+
+static unsigned int primes[26] = {61,127,251,509,1021,2039,4093,8191,16381,32749,65521,131071,262139,524287,1048573,2097143,4194301,8388593,16777213,33554393,67108859,134217689,268435399,536870909,1073741789,2147483647};
+
+static struct statelist *statelist = NULL;
+static struct multichar_symbols *mc = NULL;
+static struct lexstates *lexstates = NULL;
+static struct sigma *lexsigma = NULL;
+static struct lexc_hashtable *hashtable;
+static struct fsm *current_regex_network;
+
+static int cwordin[1000], cwordout[1000], medcwordin[2000], medcwordout[2000], carity, lexc_statecount, maxlen, hasfinal, current_entry, net_has_unknown;
+static Boolean *mchash;
+static struct lexstates *clexicon, *ctarget;
+
+static char *mystrncpy(char *dest, char *src, int len);
+static void lexc_string_to_tokens(char *string, int *intarr);
+static void lexc_pad();
+static void lexc_medpad();
+static void lexc_number_states();
+static void lexc_cleanup();
+static unsigned int lexc_suffix_hash(int offset);
+static unsigned int lexc_symbol_hash(char *s);
+static void lexc_update_unknowns(int sigma_number);
+
+static unsigned int lexc_suffix_hash(int offset) {
+    register unsigned int h = 0, g, p;
+    /* Read suffixes in cwordin[] and cwordout[] and return a hash value */
+    for(p = offset; cwordin[p] != -1; p++) {
+        h = (h << 4) + (unsigned int) (cwordin[p] | (cwordout[p] << 8));
+        if (0 != (g = h & 0xf0000000)) {
+            h = h ^ (g >> 24);
+            h = h ^ g;
+        }
+    }
+    /* No tablemod here, we decide on the table size later */
+    return h;
+}
+
+static unsigned int lexc_symbol_hash(char *s) {
+    register unsigned int hash;
+    int c;
+    hash = 5381;
+    while ((c = *s++))
+	hash = ((hash << 5) + hash) + c;
+    return (hash % SIGMA_HASH_TABLESIZE);
+}
+
+int lexc_find_sigma_hash(char *symbol) {
+    int ptr;
+    struct lexc_hashtable *h;
+    ptr = lexc_symbol_hash(symbol);
+
+    if ((hashtable+ptr)->symbol == NULL)
+        return -1;
+    for (h = (hashtable+ptr); h != NULL; h = h->next) {
+        if (strcmp(symbol,h->symbol) == 0) {
+            return (h->sigma_number);
+        }
+    }
+    return -1;
+}
+
+void lexc_add_sigma_hash(char *symbol, int number) {
+    int ptr;
+    struct lexc_hashtable *h, *hnew;
+    ptr = lexc_symbol_hash(symbol);
+
+    if (net_has_unknown == 1)
+        lexc_update_unknowns(number);
+
+    if ((hashtable+ptr)->symbol == NULL) {
+        (hashtable+ptr)->symbol = xxstrdup(symbol);
+        (hashtable+ptr)->sigma_number = number;
+        return;
+    }
+    for (h = hashtable+ptr; h->next != NULL; h = h->next) {
+    }
+    hnew = xxmalloc(sizeof(struct lexc_hashtable));
+    hnew->symbol = xxstrdup(symbol);
+    hnew->sigma_number = number;
+    h->next = hnew;
+    hnew->next = NULL;
+}
+
+void lexc_init() {
+    int i;
+    lexsigma = sigma_create();
+    mc = NULL;
+    lexstates = NULL;
+    clexicon = NULL;
+    ctarget = NULL;
+    statelist = NULL;
+    lexc_statecount = 0;
+    net_has_unknown = 0;
+    lexc_clear_current_word();
+    hashtable = xxcalloc(SIGMA_HASH_TABLESIZE, sizeof(struct lexc_hashtable));
+
+    maxlen = 0;
+
+    mchash = xxcalloc(256*256, sizeof(Boolean));
+    for (i=0; i< SIGMA_HASH_TABLESIZE; i++) {
+        (hashtable+i)->symbol = NULL;
+        (hashtable+i)->sigma_number = -1;
+        (hashtable+i)->next = NULL;
+    }
+}
+
+void lexc_clear_current_word() {
+    cwordin[0] = cwordout[0] = 0;
+    cwordin[1] = cwordout[1] = -1;
+    current_entry = WORD_ENTRY;
+}
+
+void lexc_add_state(struct states *s) {
+    struct statelist *sl;
+    sl = xxmalloc(sizeof(struct statelist));
+    sl->state = s;
+    s->number = -1;
+    sl->next = statelist;
+    sl->start = 0;
+    sl->final = 0;
+    statelist = sl;
+    lexc_statecount++;
+}
+
+/* Go through the net built so far and add new transitions for @ */
+/* to reflect the new symbols we now have in sigma */
+/* We should really build a fast lookup ptr for finding the @ transitions */
+/* But who in their right mind is ever going to use lots of @ in a lexicon construction? */
+/* Of course this only applies to the special construct < regex > inside lexicon entries */
+/* since @ is impossible to produce otherwise */
+
+void lexc_update_unknowns(int sigma_number) {
+    struct statelist *s;
+    struct states::trans *t, *newtrans;
+    for (s = statelist; s != NULL; s = s->next) {
+        if (s->state->mergeable == 2)
+            continue;
+        for (t=s->state->trans ; t!=NULL; t= t->next) {
+            if (t->in == IDENTITY || t->out == IDENTITY) {
+	        newtrans = xxmalloc(sizeof(struct states::trans));
+                newtrans->in = sigma_number;
+                newtrans->out = sigma_number;
+                newtrans->target = t->target;
+                newtrans->next = t->next;
+                t->next = newtrans;
+                }
+        }
+    }
+}
+
+void lexc_add_network() {
+
+    struct fsm *net;
+    struct fsm_state *fsm;
+    struct sigma *sigma;
+    struct states **slist, *sourcestate, *deststate, *newstate;
+    struct statelist *s;
+    struct states::trans *newtrans;
+    int i, j, *sigreplace, signumber, maxstate, *finals, unknown_symbols, first_new_sigma, *unk = NULL;
+
+    unknown_symbols = 0;
+    first_new_sigma = 0;
+    sourcestate = clexicon->state;
+    deststate = ctarget->state;
+
+    net = current_regex_network;
+    fsm = net->states;
+
+    sigreplace = xxcalloc(sigma_max(net->sigma)+1,sizeof(int));
+
+    for (sigma = net->sigma; sigma != NULL && sigma->number != -1; sigma = sigma->next) {
+        if ((signumber = lexc_find_sigma_hash(sigma->symbol)) == -1) {
+            /* Add to existing lexc sigma */
+            signumber = sigma_add(sigma->symbol, lexsigma);
+            first_new_sigma = first_new_sigma > 0 ? first_new_sigma : signumber;
+            lexc_add_sigma_hash(sigma->symbol, signumber);
+            *(sigreplace+sigma->number) = signumber;
+        } else {
+            /* We already have it, add to conversion table */
+            *(sigreplace+sigma->number) = signumber;
+        }
+    }
+
+    /* Renum arcs */
+    for (i=0, maxstate = 0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->in != -1)
+            (fsm+i)->in = *(sigreplace+(fsm+i)->in);
+        if ((fsm+i)->out != -1)
+            (fsm+i)->out = *(sigreplace+(fsm+i)->out);
+        maxstate = (fsm+i)->state_no > maxstate ? (fsm+i)->state_no : maxstate;
+        if ((fsm+i)->in == IDENTITY || (fsm+i)->in == UNKNOWN || (fsm+i)->out == UNKNOWN)
+            unknown_symbols = 1;
+    }
+    if (unknown_symbols == 1) {
+        unk = xxcalloc(sigma_max(lexsigma)+2,sizeof(int));
+        for (i=0, sigma = lexsigma; sigma != NULL && sigma->number != -1; sigma=sigma->next) {
+            if (sigma->number > 2 && sigma_find(sigma->symbol, net->sigma) == -1) {
+                *(unk+i) = sigma->number;
+                i++;
+            }
+        }
+    }
+
+    slist = xxcalloc(sizeof(**slist),maxstate+1);
+    finals = xxcalloc(sizeof(int),maxstate+1);
+
+    for (i=0; i <= maxstate;i++) {
+        newstate = xxmalloc(sizeof(struct states));
+        *(slist+i) = newstate;
+        newstate->trans = NULL;
+        newstate->lexstate = NULL;
+        newstate->number = -1;
+        newstate->hashval = -1;
+        newstate->mergeable = 0;
+        newstate->distance = 0;
+        newstate->merge_with = newstate;
+        s = xxmalloc(sizeof(struct statelist));
+        s->state = newstate;
+        s->next = statelist;
+        s->start = 0;
+        s->final = 0;
+        statelist = s;
+    }
+    /* Add an EPSILON transition from sourcestate to state 0 */
+    newtrans = xxmalloc(sizeof(struct states::trans));
+    newtrans->in = EPSILON;
+    newtrans->out = EPSILON;
+    newtrans->target = *slist;
+    newtrans->next = sourcestate->trans;
+    sourcestate->trans = newtrans;
+
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1) {
+            newstate = *(slist+(fsm+i)->state_no);
+            newtrans = xxmalloc(sizeof(struct states::trans));
+            newtrans->in = (fsm+i)->in;
+            newtrans->out = (fsm+i)->out;
+            newtrans->target = *(slist+(fsm+i)->target);
+            newtrans->next = newstate->trans;
+            newstate->trans = newtrans;
+            /* Add new symbols for @:@ transitions */
+            /* TODO: make this work for ?: or :? trans as well */
+            if (unknown_symbols == 1) {
+                if ((fsm+i)->in == IDENTITY || (fsm+i)->out == IDENTITY) {
+                    for (j=0; *(unk+j) != 0; j++) {
+                        newtrans = xxmalloc(sizeof(struct states::trans));
+                        newtrans->in = *(unk+j);
+                        newtrans->out = *(unk+j);
+                        newtrans->target = *(slist+(fsm+i)->target);
+                        newtrans->next = newstate->trans;
+                        newstate->trans = newtrans;
+                    }
+                }
+            }
+        }
+        finals[(fsm+i)->state_no] = (fsm+i)->final_state;
+    }
+    /* Add an EPSILON transition from all final states to deststate */
+    for (i=0; i <= maxstate; i++) {
+        if (finals[i] == 1) {
+            newtrans = xxmalloc(sizeof(struct states::trans));
+            newtrans->in = newtrans->out = EPSILON;
+            newtrans->target = deststate;
+            newstate = *(slist+i);
+            newtrans->next = newstate->trans;
+            newstate->trans = newtrans;
+        }
+    }
+    if (unknown_symbols == 1) {
+        xxfree(unk);
+        net_has_unknown = 1;
+    }
+    xxfree(slist);
+    xxfree(finals);
+}
+
+void lexc_set_network(struct fsm *net) {
+    current_regex_network = net;
+    current_entry = REGEX_ENTRY;
+    return;
+}
+
+void lexc_set_current_lexicon(char *name, int which) {
+    /* Sets the global lexicon variable to point to a new lexicon */
+    /* the variable which = 0 indicates source, which = 1 indicated target */
+
+    struct lexstates *l;
+    struct states *newstate;
+
+    for (l = lexstates; l != NULL; l = l->next) {
+        if (strcmp(name,l->name) == 0) {
+            if (which == 0) {
+		l->has_outgoing = 1;
+                clexicon = l;
+	    } else {
+                ctarget = l;
+	    }
+            return;
+        }
+    }
+    l = xxmalloc(sizeof(struct lexstates));
+    l->next = lexstates;
+    l->name = xxstrdup(name);
+    l->has_outgoing = 0;
+    l->targeted = 0;
+    lexstates = l;
+    newstate = xxmalloc(sizeof(struct states));
+    lexc_add_state(newstate);
+    newstate->lexstate = l;
+    newstate->trans = NULL;
+    newstate->mergeable = 0;
+    newstate->merge_with = newstate;
+    l->state = newstate;
+    if (which == 0) {
+        clexicon = l;
+	l->has_outgoing = 1;
+    } else {
+        ctarget = l;
+    }
+}
+
+char *lexc_find_delim(char *name, char delimiter, char escape) {
+    int i;
+    for (i=0; *(name+i) != '\0'; i++) {
+	if (*(name+i) == escape && *(name+i+1) != '\0') {
+	    i++;
+	    continue;
+	}
+        if (*(name+i) == delimiter) {
+            return name+i;
+        }
+    }
+    return NULL;
+}
+
+void lexc_deescape_string(char *name, char escape, int mode) {
+    int i, j;
+    for (i=0, j=0; *(name+i) != '\0'; i++) {
+        *(name+j) = *(name+i);
+        if (*(name+i) == escape) {
+            *(name+j) = *(name+i+1);
+            j++;
+            i++;
+            continue;
+        }
+	else if (mode == 1 && *(name+i) == '0') {
+	    /* Marks alignment EPSILON */
+	    *(name+j) = (unsigned char) 0xff;
+	    j++;
+	    continue;
+	}
+        else if (*(name+i) != escape && *(name+i) != '0') {
+            j++;
+            continue;
+        }
+    }
+    *(name+j) = '\0';
+}
+
+/* Read a string and fill cwordin, cwordout arrays */
+/* with the sigma numbers of the current word, -1 terminated */
+
+void lexc_set_current_word(char *name) {
+    char *instring, *outstring;
+    int i;
+
+    carity = 1;
+    instring = name;
+    outstring = lexc_find_delim(name,':','%');
+    /* printf("CWin: [%s] CWout: [%s]\n", instring, outstring); */
+    if (outstring != NULL) {
+        *outstring = '\0';
+        outstring = outstring+1;
+        lexc_deescape_string(outstring,'%',1);
+        carity = 2;
+    }
+    lexc_deescape_string(instring, '%',1);
+    /* printf("CWin2: [%s] CWout2: [%s]\n", instring, outstring); */
+    lexc_string_to_tokens(instring, cwordin);
+    if (carity == 2) {
+        lexc_string_to_tokens(outstring, cwordout);
+	if (g_lexc_align)
+	    lexc_medpad();
+	else
+	    lexc_pad();
+    } else {
+        for (i=0; *(cwordin+i) != -1; i++) {
+            *(cwordout+i) = *(cwordin+i);
+        }
+        *(cwordout+i) = -1;
+
+    }
+    current_entry = WORD_ENTRY;
+}
+
+
+#define LEV_DOWN 0
+#define LEV_LEFT 1
+#define LEV_DIAG 2
+    
+void lexc_medpad() {
+    int i, j, x, y, s1len, s2len, left, down, diag, dir;
+
+    if (*cwordin == -1 && *cwordout == -1) {
+	*cwordin = *cwordout = EPSILON;
+	*(cwordin+1) = *(cwordout+1) = -1;
+	return;
+    }
+    
+    for (i = 0, j = 0; cwordin[i] != -1; i++) {
+    	if (cwordin[i] == EPSILON) {
+    	    continue;
+    	}
+    	cwordin[j] = cwordin[i];
+    	j++;
+    }
+    cwordin[j] = -1;
+
+    for (i = 0, j = 0; cwordout[i] != -1; i++) {
+    	if (cwordout[i] == EPSILON) {
+    	    continue;
+    	}
+    	cwordout[j] = cwordout[i];
+    	j++;
+    }
+    cwordout[j] = -1;
+    
+    for (i = 0; cwordin[i] != -1; i++) { }
+    s1len = i;
+    for (i = 0; cwordout[i] != -1; i++) { }
+    s2len = i;
+    
+    int matrix[s1len+2][s2len+2];
+    int dirmatrix[s1len+2][s2len+2];
+
+    matrix[0][0] = 0;
+    dirmatrix[0][0] = 0;
+    for (x = 1; x <= s1len; x++) {
+        matrix[x][0] = matrix[x-1][0] + 1;
+	dirmatrix[x][0] = LEV_LEFT;
+    }
+    for (y = 1; y <= s2len; y++) {
+        matrix[0][y] = matrix[0][y-1] + 1;
+	dirmatrix[0][y] = LEV_DOWN;
+    }
+    for (x = 1; x <= s1len; x++) {
+        for (y = 1; y <= s2len; y++) {
+    	    diag = matrix[x-1][y-1] + (cwordin[x-1] == cwordout[y-1] ? 0 : 100);
+    	    down =  matrix[x][y-1] + 1;
+    	    left = matrix[x-1][y] + 1;
+    	    if (diag <= left && diag <= down) {
+    		matrix[x][y] = diag;
+    		dirmatrix[x][y] = LEV_DIAG;
+    	    } else if (left <= diag && left <= down) {
+    		matrix[x][y] = left;
+    		dirmatrix[x][y] = LEV_LEFT;
+    	    } else {
+    		matrix[x][y] = down ;
+    		dirmatrix[x][y] = LEV_DOWN;
+    	    }
+    	}
+    }
+
+    for (x = s1len, y = s2len, i = 0; (x > 0) || (y > 0); i++) {
+	dir = dirmatrix[x][y];
+    	if (dir == LEV_DIAG) {
+    	    medcwordin[i] = cwordin[x-1];
+    	    medcwordout[i] = cwordout[y-1];
+    	    x--;
+    	    y--;
+    	}
+    	else if (dir == LEV_DOWN) {
+    	    medcwordin[i] = EPSILON;
+    	    medcwordout[i] = cwordout[y-1];
+    	    y--;
+    	}
+    	else {
+    	    medcwordin[i] = cwordin[x-1];
+	    medcwordout[i] = EPSILON;
+    	    x--;
+    	}
+    }
+    for (j = 0, i-= 1; i >= 0; j++, i--) {
+    	cwordin[j] = medcwordin[i];
+    	cwordout[j] = medcwordout[i];
+    }
+    cwordin[j] = -1;
+    cwordout[j] = -1;
+}
+
+void lexc_pad() {
+    int i, pad;
+    /* Pad the shorter of current in, out words in cwordin, cwordout with EPSILON */
+
+    if (*cwordin == -1 && *cwordout == -1) {
+	*cwordin = *cwordout = EPSILON;
+	*(cwordin+1) = *(cwordout+1) = -1;
+	return;
+    }
+
+    for (i=0, pad = 0; ;i++) {
+        if (pad == 1 && *(cwordout+i) == -1) {
+            *(cwordin+i) = -1;
+            break;
+        }
+        if (pad == 2 && *(cwordin+i) == -1) {
+            *(cwordout+i) = -1;
+            break;
+        }
+        if (*(cwordin+i) == -1 && *(cwordout+i) != -1) {
+            pad = 1; /* Pad upper */
+        }
+        else if (*(cwordin+i) != -1 && *(cwordout+i) == -1) {
+            pad = 2; /* Pad lower */
+        }
+        if (pad == 1) {
+            *(cwordin+i) = EPSILON;
+        }
+        if (pad == 2) {
+            *(cwordout+i) = EPSILON;
+        }
+        if (pad == 0 && *(cwordin+i) == -1)
+            break;
+    }
+}
+
+void lexc_string_to_tokens(char *string, int *intarr) {
+    int len, i, pos, skip, signumber, multi;
+    unsigned int mchashval;
+    char tmpstring[5];
+    struct multichar_symbols *mcs;
+    len = strlen(string);
+    for (i=0, pos = 0; i < len; ) {
+
+	/* EPSILON for alignment is marked as 0xff */
+	if ((unsigned char) string[i] == 0xff) {
+	    *(intarr+pos) = EPSILON;
+	    pos++;
+	    i++;
+	    continue;
+	}
+
+        multi = 0;
+        mchashval = (unsigned int) ((unsigned char) *(string+i)) * 256 + (unsigned int) ((unsigned char) *(string+i+1));
+        if ((i < len-1) && *(mchash+mchashval) == 1) {
+            for (mcs = mc; mcs != NULL; mcs = mcs->next) {
+                if (strncmp(string+i,mcs->symbol,strlen(mcs->symbol)) == 0) {
+                    /* printf("Found multichar: [%s][%i]\n",mcs->symbol,mcs->sigma_number); */
+                    multi = 1;
+                    break;
+                }
+            }
+        }
+
+        if (multi) {
+            *(intarr+pos) = mcs->sigma_number;
+            pos++;
+            i += strlen(mcs->symbol);
+        } else {
+            skip = utf8skip(string+i);
+            if ((signumber = lexc_find_sigma_hash(mystrncpy(tmpstring,string+i,skip+1))) != -1) {
+                *(intarr+pos) = signumber;
+                pos++;
+                i = i + skip + 1;
+            } else {
+                signumber = sigma_add(mystrncpy(tmpstring, string+i, skip+1), lexsigma);
+                lexc_add_sigma_hash(tmpstring, signumber);
+                *(intarr+pos) = signumber;
+                pos++;
+                i = i + skip + 1;
+            }
+        }
+    }
+    *(intarr+pos) = -1;
+}
+
+char *mystrncpy(char *dest, char *src, int len) {
+    int i;
+    for (i=0; i < len; i++) {
+        *(dest+i) = *(src+i);
+        if (*(src+i) == '\0')
+            return(dest);
+    }
+    *(dest+i) = '\0';
+/*     printf("Mystrncpy: [%s]\n",dest); */
+    return(dest);
+}
+
+/* Add MC to front of chain */
+/* In decreasing order of length */
+
+void lexc_add_mc(char *symbol) {
+    int s, len;
+    unsigned int mchashval;
+    struct multichar_symbols *mcs, *mcprev, *mcnew;
+    lexc_deescape_string(symbol,'%',0);
+    if (!lexc_find_mc(symbol)) {
+        len = utf8strlen(symbol);
+        mcprev = NULL;
+        for (mcs = mc; mcs != NULL && utf8strlen(mcs->symbol) > len; mcprev = mcs, mcs=mcs->next) {
+        }
+        mcnew = xxmalloc(sizeof(struct multichar_symbols));
+        mcnew->symbol = xxstrdup(symbol);
+        mcnew->next = mcs;
+        if ((mc == NULL) ||(mcs != NULL && mcprev == NULL))
+            mc = mcnew;
+        if (mcprev != NULL)
+            mcprev->next = mcnew;
+        
+        s = sigma_add(symbol, lexsigma);
+        mchashval = (unsigned int) ((unsigned char) *(symbol)) * 256 + (unsigned int) ((unsigned char) *(symbol+1));
+        lexc_add_sigma_hash(symbol, s);
+        *(mchash+mchashval) = 1;
+        mcnew->sigma_number = s;
+    }
+}
+
+int lexc_find_mc(char *symbol) {
+    struct multichar_symbols *mcs;
+    for (mcs = mc ; mcs != NULL ; mcs = mcs->next) {
+        if (strcmp(symbol,mcs->symbol) == 0)
+            return 1;
+    }
+    return 0;
+}
+
+struct states *lexc_find_lex_state(char *name) {
+    struct lexstates *l;
+    for (l = lexstates ; l != NULL; l = l->next) {
+        if (strcmp(name,l->name) == 0)
+            return (l->state);
+    }
+    return NULL;
+}
+
+void lexc_add_word() {
+    /** Add a word from source state to destination state */
+    struct states::trans *newtrans, *trans;
+    struct states *sourcestate, *deststate, *newstate;
+    int i, follow, len;
+
+    if (current_entry == REGEX_ENTRY) {
+        lexc_add_network();
+        return;
+    }
+            
+    /* find source, dest */
+    sourcestate = clexicon->state;
+    deststate = ctarget->state;
+
+    for (i=0; *(cwordin+i) != -1; i++) {}
+    len = i;
+    maxlen = len > maxlen ? len : maxlen;
+    
+    /* We follow the source state if the symbols are the same */
+    /* To merge prefixes */
+    for (follow = 1, i=0; *(cwordin+i) != -1; i++) {
+        
+        if (follow == 1) {
+            for (trans = sourcestate->trans; trans != NULL ; trans = trans->next) {
+                if (trans->in == *(cwordin+i) && trans->out == *(cwordout+i) && trans->target->lexstate == NULL) {
+                    /* Can't follow if target needs to be lexstate */
+                    if (*(cwordin+i+1) == -1 && trans->target != deststate) {
+                        continue;
+                    }
+                    sourcestate = trans->target;
+                    sourcestate->mergeable = 0;
+                    /* Breakout */
+                    goto breakout;
+                }
+            }
+        }
+        follow = 0;
+
+        newtrans = xxmalloc(sizeof(struct states::trans));
+        if (*(cwordin+i+1) == -1) {
+            newtrans->target = deststate;
+        } else {
+            newstate = xxmalloc(sizeof(struct states));
+            lexc_add_state(newstate);
+            newtrans->target = newstate;
+            newstate->trans = NULL;
+            newstate->lexstate = NULL;
+            newstate->mergeable = 1;
+            newstate->hashval = lexc_suffix_hash(i+1);
+            newstate->distance = len - i - 1;
+            newstate->merge_with = newstate;
+        }
+        newtrans->next = sourcestate->trans;
+        sourcestate->trans = newtrans;
+
+        newtrans->in = *(cwordin+i);
+        newtrans->out = *(cwordout+i);
+
+        sourcestate = newtrans->target;
+    breakout:;
+        
+    }
+    return;
+}
+
+void lexc_number_states() {
+    int n, smax, hasroot;
+    struct statelist *s;
+    struct lexstates *l;
+
+    smax = n = hasfinal = 0;
+
+    for (hasroot = 0, s = statelist; s != NULL; s = s->next) {
+        smax++;
+        if (s->state->lexstate != NULL && strcmp(s->state->lexstate->name, "Root") == 0) {
+            s->state->number = 0;
+            s->start = 1;
+            n++;
+            hasroot = 1;
+            break;
+        }
+    }
+    /* If there is no Root lexicon, the first lexicon mentioned is Root */
+    if (!hasroot) {
+        for (s = statelist; s != NULL; s = s->next) {
+            if (s->next == NULL) {
+                s->state->number = 0;
+#ifdef ORIGINAL
+                fprintf(stderr,"*Warning: no Root lexicon, using '%s' as Root.\n",s->state->lexstate->name);
+#else
+                if (verbose_lexc_ == 1)
+                  {
+                    fprintf(stderr,"*Warning: no Root lexicon, using '%s' as Root.\n",s->state->lexstate->name);
+                    fflush(stderr);
+                  }
+#endif
+                s->start = 1;
+                n++;
+            }
+        }
+    }
+    /* Mark # as the last state */
+    for (s = statelist; s != NULL; s = s->next) {
+        if (s->state->lexstate != NULL && strcmp(s->state->lexstate->name, "#") == 0) {
+            s->state->number = smax-1;
+            s->final = 1;
+            hasfinal = 1;
+        } else if (s->state->lexstate != NULL && strcmp(s->state->lexstate->name, "#") != 0 && s->state->lexstate->has_outgoing == 0) {
+	    /* Also mark uncontinued states as final (this is warned about elsewhere) */
+            s->final = 1;
+	}
+    }
+
+    for (s = statelist; s != NULL; s = s->next) {
+        if (s->state->number == -1) {
+            s->state->number = n;
+            n++;
+        }
+    }
+    lexc_statecount = n+1;
+    for (l = lexstates; l != NULL ; l = l->next) {
+        if (l->targeted == 0 && l->state->number != 0) {
+#ifdef ORIGINAL
+	    fprintf(stderr,"*Warning: lexicon '%s' defined but not used\n",l->name);
+            fflush(stdout);
+#else
+            if (verbose_lexc_)
+              {
+                fprintf(stderr,"*Warning: lexicon '%s' defined but not used\n",l->name);
+                fflush(stderr);
+              }
+#endif
+        }
+        if (l->has_outgoing == 0 && strcmp(l->name, "#") != 0) {
+#ifdef ORIGINAL
+	    fprintf(stderr,"***Warning: lexicon '%s' used but never defined\n",l->name);
+            fflush(stdout);
+#else
+            if (verbose_lexc_)
+              {
+            fprintf(stderr,"***Warning: lexicon '%s' used but never defined\n",l->name);
+                fflush(stderr);
+              }
+
+#endif
+        }
+    }
+}
+
+int lexc_eq_paths(struct states *one, struct states *two) {
+    while (one->lexstate == NULL && two->lexstate == NULL) {
+        if (one->trans->in != two->trans->in || one->trans->out != two->trans->out)
+            return 0;
+        one = one->trans->target;
+        two = two->trans->target;
+    }
+    if (one->lexstate != two->lexstate)
+        return 0;
+    return 1;
+}
+
+void lexc_merge_states() {
+    struct lenlist {
+        struct states *state;
+        struct lenlist *next;
+    };
+    struct hashstates {
+        struct states *state;
+        struct hashstates *next;
+    } *hashstates, *currenth, *newh;
+
+    struct lenlist *lenlist, *newl, *currentl;
+    struct statelist *s, *sprev, *sf;
+    struct states *state, *purgestate;
+    struct states::trans *t, *tprev;
+    int i, numstates, tablesize, hash;
+
+    /* Create array of ptrs to states depending on string length */
+    lenlist = xxcalloc(maxlen+1,sizeof(struct lenlist));
+    numstates = 0;
+    for (s = statelist ; s!= NULL; s = s->next) {
+        if (s->state->mergeable)
+            numstates++;
+    }
+
+    /* Find a suitable prime for hashing: proportional to the size of the */
+    /* number of mergeable states */
+
+    for (i = 0; primes[i] < numstates/4; i++) { }
+    tablesize = primes[i];
+    hashstates = xxcalloc(tablesize,sizeof(struct hashstates));
+
+    for (s = statelist ; s!= NULL; s = s->next) {
+        if (s->state->mergeable) {
+            numstates++;
+            currentl = lenlist+(s->state->distance);
+            if (currentl->state == NULL)
+                currentl->state = s->state;
+            else {
+                newl = xxcalloc(1,sizeof(struct lenlist));
+                newl->state = s->state;
+                newl->next = currentl->next;
+                currentl->next = newl;
+            }
+            s->state->hashval = s->state->hashval % tablesize;
+            currenth = hashstates+s->state->hashval;
+            if (currenth->state == NULL) {
+                currenth->state = s->state;
+            } else {
+                newh = xxcalloc(1,sizeof(struct hashstates));
+                newh->state = s->state;
+                newh->next = currenth->next;
+                currenth->next = newh;
+            }
+        }
+    }
+    
+    for (i = maxlen; i >= 1 ; i--) {
+        /* printf("Analyzing: [%i]...",i); fflush(stdout); */
+        for (currentl = (lenlist+i); currentl != NULL; currentl = currentl->next) {
+            if (currentl->state == NULL)
+                break;
+            if (currentl->state->mergeable != 1)
+                continue;
+            /* Find states hashing to same value as current */
+            state = currentl->state;
+            hash = state->hashval;
+            for (currenth = hashstates+hash; currenth != NULL; currenth = currenth->next) {
+                /* Merge */
+                if (currenth->state != state && currenth->state->mergeable == 1 && currenth->state->distance == state->distance && lexc_eq_paths(currenth->state,state)) {
+                    currenth->state->merge_with = state;
+                    for (purgestate = currenth->state; purgestate->lexstate == NULL; purgestate = purgestate->trans->target) {
+                        purgestate->mergeable = 2;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Go through statelist and remove merged states and free states, trans */
+    
+    for (s = statelist, sprev = NULL; s != NULL; s = s->next) {
+        for (t = s->state->trans, tprev = NULL; t != NULL; tprev = t, t = t->next) {
+            t->target = t->target->merge_with;
+            if (tprev != NULL && s->state->mergeable == 2) {
+                xxfree(tprev);
+            } else {
+                if (t->target->lexstate != NULL)
+                    t->target->lexstate->targeted = 1;
+            }
+        }
+        if (tprev != NULL && s->state->mergeable == 2)
+            xxfree(tprev);
+    }
+    for (s = statelist, sprev = NULL; s != NULL; ) {
+        if (s->state->mergeable == 2) {
+            if (sprev != NULL) {
+                sprev->next = s->next;
+            } else {
+                statelist = s;
+            }
+            xxfree(s->state);
+            sf = s;
+            s = s->next;
+            xxfree(sf);
+        } else {
+            sprev = s;
+            s = s ->next;
+        }
+    }
+
+    /* Cleanup */
+
+    for (i = 0; i < maxlen ; i++) {
+        newl = NULL;
+        for (currentl = (lenlist+i)->next; currentl != NULL ;currentl=currentl->next) {
+            if (newl != NULL)
+                xxfree(newl);
+            newl = currentl;
+        }
+        if (newl != NULL)
+            xxfree(newl);
+    }
+    for (i = 0; i < tablesize ; i++) {
+        newh = NULL;
+        for (currenth = (hashstates+i)->next; currenth != NULL ;currenth=currenth->next) {
+            if (newh != NULL)
+                xxfree(newh);
+            newh = currenth;
+        }
+        if (newh != NULL)
+            xxfree(newh);
+    }
+    xxfree(hashstates);
+    xxfree(lenlist);
+}
+
+struct fsm *lexc_to_fsm() {
+    struct statelist *s, *sa;
+    struct fsm_state *fsm;
+    struct fsm *net;
+    struct states::trans *t;
+    int i, j,  linecount;
+
+#ifdef ORIGINAL
+    fprintf(stderr,"Building lexicon...\n");
+    fflush(stdout);
+#else
+    if (verbose_lexc_)
+      {
+        fprintf(stderr,"Building lexicon...\n");
+        fflush(stderr);
+      }
+#endif
+    lexc_merge_states();
+    net = fsm_create("");
+    xxfree(net->sigma);
+    net->sigma = lexsigma;
+    lexc_number_states();
+    if (hasfinal == 0) {
+#ifdef ORIGINAL
+        fprintf(stderr,"Warning: # is never reached!!!\n");
+#else
+        if (verbose_lexc_)
+          {
+            fprintf(stderr,"Warning: # is never reached!!!\n");
+            fflush(stderr);
+          }
+#endif
+        return(fsm_empty_set());
+    }
+    sa = xxmalloc(sizeof(struct statelist)*lexc_statecount);
+    for (s = statelist; s != NULL; s = s->next) {
+        sa[s->state->number].state = s->state;
+        sa[s->state->number].start = s->start;
+        sa[s->state->number].final = s->final;
+    }
+    linecount = 0;
+    for (s = statelist; s != NULL; s = s->next) {
+        linecount++;
+        for (t = s->state->trans; t != NULL; t = t->next)
+            linecount++;
+    }
+    fsm = xxmalloc(sizeof(struct fsm_state)*(linecount+1));
+    for (i = 0, j = 0, s = sa; j < lexc_statecount; j++) {
+        if (s[j].state->trans == NULL) {
+            add_fsm_arc(fsm,i,s[j].state->number, -1, -1, -1, s[j].final, s[j].start);
+            i++;
+        } else {
+            for (t = s[j].state->trans; t != NULL; t = t->next) {
+                add_fsm_arc(fsm,i,s[j].state->number,t->in,t->out,t->target->number,s[j].final,s[j].start);
+                i++;
+            }
+        }
+    }
+    add_fsm_arc(fsm, i, -1, -1, -1, -1, -1, -1);
+    net->states = fsm;
+    net->statecount = lexc_statecount;
+    fsm_update_flags(net, UNK, UNK, UNK, UNK, UNK, UNK);
+    if (sigma_find_number(EPSILON, lexsigma) == -1)
+        sigma_add_special(EPSILON, lexsigma);
+    xxfree(s);
+    lexc_cleanup();
+    sigma_cleanup(net,0);
+    sigma_sort(net);
+    
+#ifdef ORIGINAL
+    fprintf(stderr,"Determinizing...\n");
+    fflush(stdout);
+#else
+    if (verbose_lexc_)
+      {
+        fprintf(stderr,"Determinizing...\n");
+        fflush(stderr);
+      }
+#endif
+    net = fsm_determinize(net);
+#ifdef ORIGINAL
+    fprintf(stderr,"Minimizing...\n");
+    fflush(stdout);
+#else
+    if (verbose_lexc_)
+      {
+        fprintf(stderr,"Minimizing...\n");
+        fflush(stderr);
+      }
+#endif
+    net = fsm_topsort(fsm_minimize(net));
+#ifdef ORIGINAL
+    fprintf(stderr,"Done!\n");
+#else
+    if (verbose_lexc_)
+      {
+        fprintf(stderr,"Done!\n");
+        fflush(stderr);
+      }
+#endif
+    return(net);
+}
+
+void lexc_cleanup() {
+    struct lexstates *l, *ln;
+    struct statelist *s, *sn;
+    struct states::trans *t, *tn;
+    struct multichar_symbols *mcs, *mcsn;
+    struct lexc_hashtable *lhash, *lprev;
+    int i;
+    xxfree(mchash);
+    for (i=0; i < SIGMA_HASH_TABLESIZE; i++) {
+        for (lhash = hashtable+i; lhash != NULL; ) {
+            if (lhash->symbol != NULL) {
+                xxfree(lhash->symbol);
+            }
+            lprev = lhash;
+            lhash = lhash->next;
+            if (lprev != hashtable+i) { xxfree(lprev); }
+        }
+    }
+    xxfree(hashtable);
+    for (mcs = mc ; mcs != NULL ; mcs = mcsn) {
+        mcsn = mcs->next;
+	xxfree(mcs->symbol);
+        xxfree(mcs);
+    }
+    for (l = lexstates ; l != NULL ; l = ln) {
+        ln = l->next;
+        xxfree(l->name);
+        xxfree(l);
+    }
+    for (s = statelist; s != NULL; s = s->next) {
+        for (t = s->state->trans; t != NULL; t = tn) {
+            tn = t->next;
+            xxfree(t);
+        }
+        xxfree(s->state);
+    }
+    for (s = statelist; s != NULL; s = sn) {
+        sn = s->next;
+        xxfree(s);
+    }
+}
diff --git a/back-ends/foma/cpp-version/mem.cc b/back-ends/foma/cpp-version/mem.cc
new file mode 100644
index 0000000..60078f3
--- /dev/null
+++ b/back-ends/foma/cpp-version/mem.cc
@@ -0,0 +1,104 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2015 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include "foma.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Global variables */
+// HFST MODIFICATIONS: Defined here, declared extern in foma.h
+struct defined_networks   *g_defines;
+struct defined_functions  *g_defines_f;
+int g_show_flags = 0;
+int g_obey_flags = 1;
+int g_flag_is_epsilon = 0;
+int g_print_space = 0;
+int g_print_pairs = 0;
+int g_minimal = 1;
+int g_name_nets = 0;
+int g_print_sigma = 1;
+int g_quit_on_fail = 1;
+int g_quote_special = 0;
+int g_recursive_define = 0;
+int g_sort_arcs = 1;
+int g_verbose = 1;
+int g_minimize_hopcroft = 1;
+int g_compose_tristate = 0;
+int g_list_limit = 100;
+int g_list_random_limit = 15;
+int g_med_limit  = 3;
+int g_med_cutoff = 15;
+int g_lexc_align = 0;
+char *g_att_epsilon = "@0@";
+
+char *xxstrndup(const char *s, size_t n) {
+    char *r = NULL;
+    const char *p = s;
+    while(*p++ && n--);
+    n = p - s - 1;
+    r = (char *) xxmalloc(n + 1);
+    if(r != NULL) {
+        memcpy(r, s, n);
+        r[n] = 0;
+    }
+    return r;
+}
+
+int next_power_of_two(int v) {
+    int i;
+    for (i=0; v > 0; i++)
+        v = v >> 1;
+    return (1 << i);
+}
+
+unsigned int round_up_to_power_of_two(unsigned int v) {
+    v--;
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v++;
+    return(v);
+}
+
+INLINE void *xxmalloc(size_t size) {
+    return(malloc(size));
+}
+
+INLINE void xxfree(void *ptr) {
+    free(ptr);
+}
+
+void *xxrealloc(void *ptr, size_t size) {
+    return(realloc(ptr, size));
+}
+
+INLINE void *xxcalloc(size_t nmemb, size_t size) {
+    return(calloc(nmemb,size));
+}
+
+INLINE char *xxstrdup(const char *s) {
+  //    return(strdup(s));
+  size_t size = strlen(s) + 1;
+  char *p = (char*)malloc(size);
+  if (p) {
+    memcpy(p, s, size);
+  }
+  return p;
+}
+
diff --git a/back-ends/foma/cpp-version/minimize.cc b/back-ends/foma/cpp-version/minimize.cc
new file mode 100644
index 0000000..7a02dc7
--- /dev/null
+++ b/back-ends/foma/cpp-version/minimize.cc
@@ -0,0 +1,676 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include "foma.h"
+
+static struct fsm *fsm_minimize_brz(struct fsm *net);
+static struct fsm *fsm_minimize_hop(struct fsm *net);
+static struct fsm *rebuild_machine(struct fsm *net);
+
+static int *single_sigma_array, *double_sigma_array, *memo_table, *temp_move, *temp_group, maxsigma, epsilon_symbol, num_states, num_symbols, num_finals, mainloop, total_states;
+
+static Boolean *finals;
+
+struct statesym {
+    int target;
+    unsigned short int symbol;
+    struct state_list *states;
+    struct statesym *next;
+};
+
+struct state_list {
+    int state;
+    struct state_list *next;
+};
+
+struct p {
+    struct e *first_e;
+    struct e *last_e;
+    struct p *current_split;
+    struct p *next;
+    struct agenda *agenda;
+    int count;
+    int t_count;
+    int inv_count;
+    int inv_t_count;
+};
+
+struct e {
+  struct p *group;
+  struct e *left;
+  struct e *right;
+  int inv_count;
+};
+
+struct agenda {
+  struct p *p;
+  struct agenda *next;
+  Boolean index;
+};
+
+// HFST MODIFICATIONS: struct trans_list -> struct trans_list_struct
+//                     struct trans_array -> struct trans_list_array
+// because some compilers complain about struct and variable having the same name
+
+static struct trans_list_struct {
+    int inout;
+    int source;
+} *trans_list;
+
+
+static struct trans_array_struct {
+    struct trans_list_struct *transitions;
+    unsigned int size;
+    unsigned int tail;
+} *trans_array;
+
+static struct p *P, *Phead, *Pnext, *current_w;
+static struct e *E;
+static struct agenda *Agenda_head, *Agenda_top, *Agenda_next, *Agenda;
+
+static INLINE int refine_states(int sym);
+static void init_PE();
+static void agenda_add(struct p *pptr, int start);
+static void sigma_to_pairs(struct fsm *net);
+/* static void single_symbol_to_symbol_pair(int symbol, int *symbol_in, int *symbol_out); */
+static INLINE int symbol_pair_to_single_symbol(int in, int out);
+static void generate_inverse(struct fsm *net);
+
+struct fsm *fsm_minimize(struct fsm *net) {
+    extern int g_minimal;
+    extern int g_minimize_hopcroft;
+
+    if (net == NULL) { return NULL; }
+    /* The network needs to be deterministic and trim before we minimize */
+    if (net->is_deterministic != YES)
+        net = fsm_determinize(net);
+    if (net->is_pruned != YES)
+        net = fsm_coaccessible(net);
+    if (net->is_minimized != YES && g_minimal == 1) {
+        if (g_minimize_hopcroft != 0) {
+            net = fsm_minimize_hop(net);
+        }
+        else
+            net = fsm_minimize_brz(net);
+        fsm_update_flags(net,YES,YES,YES,YES,UNK,UNK);
+    }
+    return(net);
+}
+
+static struct fsm *fsm_minimize_brz(struct fsm *net) {
+    return(fsm_determinize(fsm_reverse(fsm_determinize(fsm_reverse(net)))));
+}
+
+static struct fsm *fsm_minimize_hop(struct fsm *net) {
+
+    struct e *temp_E;
+    struct trans_array_struct *tptr;
+    struct trans_list_struct *transitions;
+    int i,j,minsym,next_minsym,current_i, stateno, thissize, source;
+    unsigned int tail;
+
+    fsm_count(net);
+    if (net->finalcount == 0)  {
+	fsm_destroy(net);
+	return(fsm_empty_set());
+    }
+
+    num_states = net->statecount;
+    
+    P = NULL;
+
+    /*
+       1. generate the inverse lookup table
+       2. generate P and E (partitions, states linked list)
+       3. Init Agenda = {Q, Q-F}
+       4. Split until Agenda is empty
+    */
+    
+    sigma_to_pairs(net);
+    
+    init_PE();
+
+    if (total_states == num_states) {
+        goto bail;
+    }
+
+    generate_inverse(net);
+
+
+    Agenda_head->index = 0;
+    if (Agenda_head->next != NULL)
+        Agenda_head->next->index = 0;
+
+    for (Agenda = Agenda_head; Agenda != NULL; ) {
+        /* Remove current_w from agenda */
+        current_w = Agenda->p;
+        current_i = Agenda->index;
+        Agenda->p->agenda = NULL;
+        Agenda = Agenda->next;
+
+        /* Store current group state number in tmp_group */
+        /* And figure out minsym */
+        /* If index is 0 we start splitting from the first symbol */
+        /* Otherwise we split from where we left off last time */
+
+        thissize = 0;
+        minsym = INT_MAX;
+        for (temp_E = current_w->first_e; temp_E != NULL; temp_E = temp_E->right) {
+            stateno = temp_E - E;
+            *(temp_group+thissize) = stateno;
+            thissize++;
+            tptr = trans_array+stateno;
+            /* Clear tails if symloop should start from 0 */
+            if (current_i == 0)
+                tptr->tail = 0;
+            
+            tail = tptr->tail;
+            transitions = (tptr->transitions)+tail;
+            if (tail < tptr->size && transitions->inout < minsym) {
+                minsym = transitions->inout;
+            }
+        }
+
+        for (next_minsym = INT_MAX; minsym != INT_MAX ; minsym = next_minsym, next_minsym = INT_MAX) {
+
+            /* Add states to temp_move */
+            for (i = 0, j = 0; i < thissize; i++) {
+                tptr = trans_array+*(temp_group+i);
+                tail = tptr->tail;
+                transitions = (tptr->transitions)+tail;
+                while (tail < tptr->size && transitions->inout == minsym) {
+                    source = transitions->source;
+                    if (*(memo_table+(source)) != mainloop) {
+                        *(memo_table+(source)) = mainloop;
+                        *(temp_move+j) = source;
+                        j++;
+                    }
+                    tail++;
+                    transitions++;
+                }
+                tptr->tail = tail;
+                if (tail < tptr->size && transitions->inout < next_minsym) {
+                    next_minsym = transitions->inout;
+                }
+            }
+            if (j == 0) {
+                continue;
+            }
+            mainloop++;
+            if (refine_states(j) == 1) {
+                break; /* break loop if we split current_w */
+            }
+        }
+        if (total_states == num_states) {
+            break;
+        }
+    }
+
+    net = rebuild_machine(net);
+
+    xxfree(trans_array);
+    xxfree(trans_list);
+
+ bail:
+    
+    xxfree(Agenda_top);
+    
+    xxfree(memo_table);
+    xxfree(temp_move);
+    xxfree(temp_group);
+
+
+    xxfree(finals);
+    xxfree(E);
+    xxfree(Phead);
+    xxfree(single_sigma_array);
+    xxfree(double_sigma_array);
+    
+    return(net);
+}
+
+static struct fsm *rebuild_machine(struct fsm *net) {
+  int i,j, group_num, source, target, new_linecount = 0, arccount = 0;
+  struct fsm_state *fsm;
+  struct p *myp;
+  struct e *thise;
+
+  if (net->statecount == total_states) {
+      return(net);
+  }
+  fsm = net->states;
+
+  /* We need to make sure state 0 is first in its group */
+  /* to get the proper numbering of states */
+
+  if (E->group->first_e != E) {
+    E->group->first_e = E;
+  }
+
+  /* Recycling t_count for group numbering use here */
+
+  group_num = 1;
+  myp = P;
+  while (myp != NULL) {
+    myp->count = 0;
+    myp = myp->next;
+  }
+
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    thise = E+((fsm+i)->state_no);
+    if (thise->group->first_e == thise) {
+      new_linecount++;
+      if ((fsm+i)->start_state == 1) {
+	thise->group->t_count = 0;
+	thise->group->count = 1;
+      } else if (thise->group->count == 0) {
+	thise->group->t_count = group_num++;
+	thise->group->count = 1;
+      }
+    }
+  }
+
+  for (i=0, j=0; (fsm+i)->state_no != -1; i++) {
+    thise = E+((fsm+i)->state_no);
+    if (thise->group->first_e == thise) {
+      source = thise->group->t_count;
+      target = ((fsm+i)->target == -1) ? -1 : (E+((fsm+i)->target))->group->t_count;
+      add_fsm_arc(fsm, j, source, (fsm+i)->in, (fsm+i)->out, target, finals[(fsm+i)->state_no], (fsm+i)->start_state);
+      arccount = ((fsm+i)->target == -1) ? arccount : arccount+1;
+      j++;
+    }
+  }
+  
+  add_fsm_arc(fsm, j, -1, -1, -1, -1, -1, -1);
+  fsm = (struct fsm_state *)(struct fsm_state *)xxrealloc(fsm,sizeof(struct fsm_state)*(new_linecount+1));
+  net->states = fsm;
+  net->linecount = j+1;
+  net->arccount = arccount;
+  net->statecount = total_states;
+  return(net);
+}
+
+static INLINE int refine_states(int invstates) {
+    int i, selfsplit;
+    struct e *thise;
+    struct p *tP, *newP = NULL;
+
+  /*
+     1. add inverse(P,a) to table of inverses, disallowing duplicates
+     2. first pass on S, touch each state once, increasing P->t_count
+     3. for each P where counter != count, split and add to agenda
+  */
+
+  /* Inverse to table of inverses */
+  selfsplit = 0;
+
+  /* touch and increase P->counter */
+  for (i=0; i < invstates; i++) {
+    ((E+(*(temp_move+i)))->group)->t_count++;
+    ((E+(*(temp_move+i)))->group)->inv_t_count += ((E+(*(temp_move+i)))->inv_count);
+    assert((E+(*(temp_move+i)))->group->t_count <= (E+(*(temp_move+i)))->group->count);
+  }
+
+  /* Split (this is the tricky part) */
+  
+  for (i=0; i < invstates; i++) {
+    
+    thise = E+*(temp_move+i);
+    tP = thise->group;
+    
+    /* Do we need to split?
+       if we've touched as many states as there are in the partition
+       we don't split */
+
+    if (tP->t_count == tP->count) {
+      tP->t_count = 0;
+      tP->inv_t_count = 0;
+      continue;
+    }
+    
+    if ((tP->t_count != tP->count) && (tP->count > 1) && (tP->t_count > 0)) {
+        
+        /* Check if we already split this */
+        newP = tP->current_split;
+        if (newP == NULL) {
+            /* printf("tP [%i] newP [%i]\n",tP->inv_count,tP->inv_t_count); */
+            /* Create new group newP */
+            total_states++;
+            if (total_states == num_states)
+                return(1); /* Abort now, machine is already minimal */
+            tP->current_split = Pnext++;
+            newP = tP->current_split;
+            newP->first_e = newP->last_e = thise;
+            newP->count = 0;
+            newP->inv_count = tP->inv_t_count;
+            newP->inv_t_count = 0;
+            newP->t_count = 0;
+            newP->current_split = NULL;
+            newP->agenda = NULL;
+
+            /* Add to agenda */
+            
+            /* If the current block (tP) is on the agenda, we add both back */
+            /* to the agenda */
+            /* In practice we need only add newP since tP stays where it is */
+            /* However, we mark the larger one as not starting the symloop */
+            /* from zero */
+            if (tP->agenda != NULL) {
+                /* Is tP smaller */
+                if (tP->inv_count < tP->inv_t_count) {
+                    agenda_add(newP, 1);
+                    tP->agenda->index = 0;
+                }
+                else {
+                    agenda_add(newP, 0);
+                }
+                /* In the event that we're splitting the partition we're currently */
+                /* splitting with, we can simply add both new partitions to the agenda */
+                /* and break out of the entire sym loop after we're */
+                /* done with the current sym and move on with the agenda */
+                /* We process the larger one for all symbols */
+                /* and the smaller one for only the ones remaining in this symloop */
+
+            } else if (tP == current_w) {
+                agenda_add(((tP->inv_count < tP->inv_t_count) ? tP : newP),0);
+                agenda_add(((tP->inv_count >= tP->inv_t_count) ? tP : newP),1);
+                selfsplit = 1;
+            } else {
+                /* If the block is not on the agenda, we add */
+                /* the smaller of tP, newP and start the symloop from 0 */
+                agenda_add((tP->inv_count < tP->inv_t_count ? tP : newP),0);
+            }
+            /* Add to middle of P-chain */
+            newP->next = P->next;
+            P->next = newP;
+        }
+    
+        thise->group = newP;
+        newP->count++;
+        
+        /* need to make tP->last_e point to the last untouched e */
+        if (thise == tP->last_e)
+            tP->last_e = thise->left;
+        if (thise == tP->first_e)
+            tP->first_e = thise->right;
+        
+        /* Adjust links */
+        if (thise->left != NULL)
+            thise->left->right = thise->right;
+        if (thise->right != NULL)
+            thise->right->left = thise->left;
+        
+        if (newP->last_e != thise) {
+            newP->last_e->right = thise;
+            thise->left = newP->last_e;
+            newP->last_e = thise;
+        }
+    
+        thise->right = NULL;
+        if (newP->first_e == thise)
+            thise->left = NULL;
+        
+        /* Are we done for this block? Adjust counters */
+        if (newP->count == tP->t_count) {
+            tP->count = tP->count - newP->count;
+            tP->inv_count = tP->inv_count - tP->inv_t_count;
+            tP->current_split = NULL;
+            tP->t_count = 0;
+            tP->inv_t_count = 0;
+        }
+    }
+  }
+  /* We return 1 if we just split the partition we were working with */
+  return (selfsplit);
+}
+
+static void agenda_add(struct p *pptr, int start) {
+
+  /* Use FILO strategy here */
+
+  struct agenda *ag;
+  //ag = xxmalloc(sizeof(struct agenda));
+  ag = Agenda_next++;
+  if (Agenda != NULL)
+    ag->next = Agenda;
+  else
+    ag->next = NULL;
+  ag->p = pptr;
+  ag->index = start;
+  Agenda = ag;
+  pptr->agenda = ag;
+}
+
+static void init_PE() {
+  /* Create two members of P
+     (nonfinals,finals)
+     and put both of them on the agenda
+  */
+
+  int i;
+  struct e *last_f, *last_nonf;
+  struct p *nonFP, *FP;
+  struct agenda *ag;
+
+  mainloop = 1;
+  memo_table = (int *)xxcalloc(num_states,sizeof(int));
+  temp_move = (int *)xxcalloc(num_states,sizeof(int));
+  temp_group = (int *)xxcalloc(num_states,sizeof(int));
+  Phead = P = Pnext = (struct p *)xxcalloc(num_states+1, sizeof(struct p));
+  nonFP = Pnext++;
+  FP = Pnext++;
+  nonFP->next = FP;
+  nonFP->count = num_states-num_finals;
+  FP->next = NULL;
+  FP->count = num_finals;
+  FP->t_count = 0;
+  nonFP->t_count = 0;
+  FP->current_split = NULL;
+  nonFP->current_split = NULL;
+  FP->inv_count = nonFP->inv_count = FP->inv_t_count = nonFP->inv_t_count = 0;
+  
+  /* How many groups can we put on the agenda? */
+  Agenda_top = Agenda_next = (struct agenda *)xxcalloc(num_states*2, sizeof(struct agenda));
+  Agenda_head = NULL;
+
+  P = NULL;
+  total_states = 0;
+
+  if (num_finals > 0) {
+      ag = Agenda_next++;
+      FP->agenda = ag;
+      P = FP;
+      P->next = NULL;
+      ag->p = FP;
+      Agenda_head = ag;
+      ag->next = NULL;
+      total_states++;
+  }
+  if (num_states - num_finals > 0) {
+      ag = Agenda_next++;
+      nonFP->agenda = ag;
+      ag->p = nonFP;
+      ag->next = NULL;
+      total_states++;
+      if (Agenda_head != NULL) {
+          Agenda_head->next = ag;
+          P->next = nonFP;
+          P->next->next = NULL;
+      } else {
+          P = nonFP;
+          P->next = NULL;
+          Agenda_head = ag;
+      }
+  }
+  
+  /* Initialize doubly linked list E */
+  E = (struct e *)xxcalloc(num_states,sizeof(struct e));
+
+  last_f = NULL;
+  last_nonf = NULL;
+  
+  for (i=0; i < num_states; i++) {
+    if (finals[i]) {
+      (E+i)->group = FP;
+      (E+i)->left = last_f;
+      if (i > 0 && last_f != NULL)
+	last_f->right = (E+i);
+      if (last_f == NULL)
+	FP->first_e = (E+i);
+      last_f = (E+i);
+      FP->last_e = (E+i);
+    } else {
+      (E+i)->group = nonFP;
+      (E+i)->left = last_nonf;
+      if (i > 0 && last_nonf != NULL)
+	last_nonf->right = (E+i);
+      if (last_nonf == NULL)
+	nonFP->first_e = (E+i);
+      last_nonf = (E+i);
+      nonFP->last_e = (E+i);
+    }
+    (E+i)->inv_count = 0;
+  }
+
+  if (last_f != NULL)
+    last_f->right = NULL;
+  if (last_nonf != NULL)
+    last_nonf->right = NULL;
+}
+
+static int trans_sort_cmp(const void *a, const void *b) {
+  return (((const struct trans_list_struct *)a)->inout - ((const struct trans_list_struct *)b)->inout);
+}
+
+static void generate_inverse(struct fsm *net) {
+    
+    struct fsm_state *fsm;
+    struct trans_array_struct *tptr;
+    struct trans_list_struct *listptr;
+
+    int i, source, target, offsetcount, symbol, size;
+    fsm = net->states;
+    trans_array = (struct trans_array_struct *)xxcalloc(net->statecount, sizeof(struct trans_array_struct));
+    trans_list = (struct trans_list_struct *)xxcalloc(net->arccount, sizeof(struct trans_list_struct));
+
+    /* Figure out the number of transitions each one has */
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target == -1) {
+            continue;
+        }
+        target = (fsm+i)->target;
+        (E+target)->inv_count++;
+        (E+target)->group->inv_count++;
+        (trans_array+target)->size++;
+    }
+    offsetcount = 0;
+    for (i=0; i < net->statecount; i++) {
+        (trans_array+i)->transitions = trans_list + offsetcount;
+        offsetcount += (trans_array+i)->size;
+    }
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target == -1) {
+            continue;
+        }
+        symbol = symbol_pair_to_single_symbol((fsm+i)->in,(fsm+i)->out);
+        source = (fsm+i)->state_no;
+        target = (fsm+i)->target;
+        tptr = trans_array + target;
+        ((tptr->transitions)+(tptr->tail))->inout = symbol;
+        ((tptr->transitions)+(tptr->tail))->source = source;
+        tptr->tail++;
+    }
+    /* Sort arcs */
+    for (i=0; i < net->statecount; i++) {
+        listptr = (trans_array+i)->transitions;
+        size = (trans_array+i)->size;
+        if (size > 1)
+            qsort(listptr, size, sizeof(struct trans_list_struct), trans_sort_cmp);
+    }
+}
+
+static void sigma_to_pairs(struct fsm *net) {
+    
+  int i, j, x, y, z, next_x = 0;
+  struct fsm_state *fsm;
+
+  fsm = net->states;
+  
+  epsilon_symbol = -1;
+  maxsigma = sigma_max(net->sigma);
+
+  maxsigma++;
+
+  single_sigma_array = (int *)xxmalloc(2*maxsigma*maxsigma*sizeof(int));
+  double_sigma_array = (int *)xxmalloc(maxsigma*maxsigma*sizeof(int));
+  
+  for (i=0; i < maxsigma; i++) {
+    for (j=0; j< maxsigma; j++) {
+      *(double_sigma_array+maxsigma*i+j) = -1;
+    }
+  }
+  
+  /* f(x) -> y,z sigma pair */
+  /* f(y,z) -> x simple entry */
+  /* if exists f(n) <-> EPSILON, EPSILON, save n */
+  /* symbol(x) x>=1 */
+
+  /* Forward mapping: */
+  /* *(double_sigma_array+maxsigma*in+out) */
+
+  /* Backmapping: */
+  /* *(single_sigma_array+(symbol*2) = in(symbol) */
+  /* *(single_sigma_array+(symbol*2+1) = out(symbol) */
+
+  /* Table for checking whether a state is final */
+
+  finals = (bool *)xxcalloc(num_states, sizeof(Boolean));
+  x = 0; num_finals = 0;
+  net->arity = 1;
+  for (i=0; (fsm+i)->state_no != -1; i++) {
+    if ((fsm+i)->final_state == 1 && finals[(fsm+i)->state_no] != 1) {
+      num_finals++;
+      finals[(fsm+i)->state_no] = 1;
+    }
+    y = (fsm+i)->in;
+    z = (fsm+i)->out;
+    if (y != z || y == UNKNOWN || z == UNKNOWN)
+        net->arity = 2;
+    if ((y == -1) || (z == -1))
+      continue;
+    if (*(double_sigma_array+maxsigma*y+z) == -1) {
+      *(double_sigma_array+maxsigma*y+z) = x;
+      *(single_sigma_array+next_x) = y;
+      next_x++;
+      *(single_sigma_array+next_x) = z;
+      next_x++;
+      if (y == EPSILON && z == EPSILON) {
+	epsilon_symbol = x;
+      }
+      x++;
+    }
+  }
+  num_symbols = x;
+}
+
+static INLINE int symbol_pair_to_single_symbol(int in, int out) {
+  return(*(double_sigma_array+maxsigma*in+out));
+}
diff --git a/back-ends/foma/cpp-version/regex.cc b/back-ends/foma/cpp-version/regex.cc
new file mode 100644
index 0000000..71eb012
--- /dev/null
+++ b/back-ends/foma/cpp-version/regex.cc
@@ -0,0 +1,3345 @@
+/* A Bison parser, made by GNU Bison 2.5.  */
+
+/* Bison implementation for Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+   
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+   
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.5"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 1
+
+
+
+/* Copy the first part of user declarations.  */
+
+/* Line 268 of yacc.c  */
+#line 18 "regex.y"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "foma.h"
+#define MAX_F_RECURSION 100
+extern int my_yyparse(char *my_string, int lineno, struct defined_networks *defined_nets, struct defined_functions *defined_funcs);
+struct fsm *current_parse;
+int rewrite, rule_direction;
+int substituting = 0;
+static char *subval1, *subval2;
+struct fsmcontexts *contexts;
+struct fsmrules *rules;
+struct rewrite_set *rewrite_rules;
+static struct fsm *fargs[100][MAX_F_RECURSION];  /* Function arguments [number][frec] */
+static int frec = -1;                            /* Current depth of function recursion */
+static char *fname[MAX_F_RECURSION];             /* Function names */
+static int fargptr[MAX_F_RECURSION];             /* Current argument no. */
+/* Variable to produce internal symbols */
+unsigned int g_internal_sym = 23482342;
+
+void add_function_argument(struct fsm *net) {
+    fargs[fargptr[frec]][frec] = net;
+    fargptr[frec]++;
+}
+
+void declare_function_name(char *s) {
+    if (frec > MAX_F_RECURSION) {
+        printf("Function stack depth exceeded. Aborting.\n");
+        exit(1);
+    }
+    fname[frec] = xxstrdup(s);
+    xxfree(s);
+}
+
+struct fsm *function_apply(struct defined_networks *defined_nets, struct defined_functions *defined_funcs) {
+    int i, mygsym, myfargptr;
+    char *regex;
+    char repstr[13], oldstr[13];
+    if ((regex = find_defined_function(defined_funcs, fname[frec],fargptr[frec])) == NULL) {
+        fprintf(stderr, "***Error: function %s@%i) not defined!\n",fname[frec], fargptr[frec]);
+        return NULL;
+    }
+    regex = xxstrdup(regex);
+    mygsym = g_internal_sym;
+    myfargptr = fargptr[frec];
+    /* Create new regular expression from function def. */
+    /* and parse that */
+    for (i = 0; i < fargptr[frec]; i++) {
+        sprintf(repstr,"%012X",g_internal_sym);
+        sprintf(oldstr, "@ARGUMENT%02i@", (i+1));
+        streqrep(regex, oldstr, repstr);
+        /* We temporarily define a network and save argument there */
+        /* The name is a running counter g_internal_sym */
+        add_defined(defined_nets, fargs[i][frec], repstr);
+        g_internal_sym++;
+    }
+    my_yyparse(regex,1,defined_nets, defined_funcs);
+    for (i = 0; i < myfargptr; i++) {
+        sprintf(repstr,"%012X",mygsym);
+        /* Remove the temporarily defined network */
+        remove_defined(defined_nets, repstr);
+        mygsym++;
+    }
+    xxfree(fname[frec]);
+    frec--;
+    xxfree(regex);
+    return(current_parse);
+}
+
+void add_context_pair(struct fsm *L, struct fsm *R) {
+    struct fsmcontexts *newcontext;
+    newcontext = (struct fsmcontexts*)xxcalloc(1,sizeof(struct fsmcontexts));
+    newcontext->left = L;
+    newcontext->right = R;
+    newcontext->next = contexts;
+    contexts = newcontext;
+}
+
+void clear_rewrite_ruleset(struct rewrite_set *rewrite_rules) {
+    struct rewrite_set *rule, *rulep;
+    struct fsmcontexts *contexts, *contextsp;
+    struct fsmrules *r, *rp;
+    for (rule = rewrite_rules; rule != NULL; rule = rulep) {
+
+	for (r = rule->rewrite_rules ; r != NULL; r = rp) {
+	    fsm_destroy(r->left);
+	    fsm_destroy(r->right);
+	    fsm_destroy(r->right2);
+	    fsm_destroy(r->cross_product);
+	    rp = r->next;
+	    xxfree(r);
+	}
+	
+	for (contexts = rule->rewrite_contexts; contexts != NULL ; contexts = contextsp) {
+
+	    contextsp = contexts->next;
+	    fsm_destroy(contexts->left);
+	    fsm_destroy(contexts->right);
+	    fsm_destroy(contexts->cpleft);
+	    fsm_destroy(contexts->cpright);
+	    xxfree(contexts);
+	}
+       	rulep = rule->next;
+	//fsm_destroy(rules->cpunion);
+	xxfree(rule);
+    }
+}
+
+void add_rewrite_rule() {
+    struct rewrite_set *new_rewrite_rule;
+    if (rules != NULL) {
+        new_rewrite_rule = (struct rewrite_set*)xxmalloc(sizeof(struct rewrite_set));
+        new_rewrite_rule->rewrite_rules = rules;
+        new_rewrite_rule->rewrite_contexts = contexts;
+        new_rewrite_rule->next = rewrite_rules;
+        new_rewrite_rule->rule_direction = rule_direction;
+
+        rewrite_rules = new_rewrite_rule;
+        rules = NULL;
+        contexts = NULL;
+        rule_direction = 0;
+    }
+}
+
+void add_eprule(struct fsm *R, struct fsm *R2, int type) {
+    struct fsmrules *newrule;
+    rewrite = 1;
+    newrule = (struct fsmrules*)xxmalloc(sizeof(struct fsmrules));
+    newrule->left = fsm_empty_string();
+    newrule->right = R;
+    newrule->right2 = R2;
+    newrule->arrow_type = type;
+    newrule->next = rules;
+    rules = newrule;
+}
+ 
+void add_rule(struct fsm *L, struct fsm *R, struct fsm *R2, int type) {
+    struct fsm *test;
+    struct fsmrules *newrule;
+    rewrite = 1;
+    newrule = (struct fsmrules*)xxmalloc(sizeof(struct fsmrules));
+
+    if ((type & ARROW_DOTTED) != 0) {
+        newrule->left = fsm_minus(fsm_copy(L), fsm_empty_string());
+    } else {
+        newrule->left = L;
+    }
+    newrule->right = R;
+    newrule->right2 = R2;
+    newrule->next = rules;
+    newrule->arrow_type = type;
+    if ((type & ARROW_DOTTED) != 0) {
+        newrule->arrow_type = type - ARROW_DOTTED;
+    }
+
+    rules = newrule;
+
+    if ((type & ARROW_DOTTED) != 0) {
+        /* Add empty [..] -> B for dotted rules (only if LHS contains the empty string) */
+        test = fsm_intersect(L,fsm_empty_string());
+        if (!fsm_isempty(test)) {
+	    newrule = (struct fsmrules*)xxmalloc(sizeof(struct fsmrules));
+            newrule->left = test;
+            newrule->right = fsm_copy(R);
+            newrule->right2 = fsm_copy(R2);
+            newrule->next = rules;
+            newrule->arrow_type = type;
+            rules = newrule;
+        } else {
+	    //fsm_destroy(test);
+	}
+    }
+}
+
+
+
+
+/* Line 268 of yacc.c  */
+#line 252 "regex.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NET = 258,
+     END = 259,
+     LBRACKET = 260,
+     RBRACKET = 261,
+     LPAREN = 262,
+     RPAREN = 263,
+     ENDM = 264,
+     ENDD = 265,
+     CRESTRICT = 266,
+     CONTAINS = 267,
+     CONTAINS_OPT_ONE = 268,
+     CONTAINS_ONE = 269,
+     XUPPER = 270,
+     XLOWER = 271,
+     FLAG_ELIMINATE = 272,
+     IGNORE_ALL = 273,
+     IGNORE_INTERNAL = 274,
+     CONTEXT = 275,
+     NCONCAT = 276,
+     MNCONCAT = 277,
+     MORENCONCAT = 278,
+     LESSNCONCAT = 279,
+     DOUBLE_COMMA = 280,
+     COMMA = 281,
+     SHUFFLE = 282,
+     PRECEDES = 283,
+     FOLLOWS = 284,
+     RIGHT_QUOTIENT = 285,
+     LEFT_QUOTIENT = 286,
+     INTERLEAVE_QUOTIENT = 287,
+     UQUANT = 288,
+     EQUANT = 289,
+     VAR = 290,
+     IN = 291,
+     IMPLIES = 292,
+     BICOND = 293,
+     EQUALS = 294,
+     NEQ = 295,
+     SUBSTITUTE = 296,
+     SUCCESSOR_OF = 297,
+     PRIORITY_UNION_U = 298,
+     PRIORITY_UNION_L = 299,
+     LENIENT_COMPOSE = 300,
+     TRIPLE_DOT = 301,
+     LDOT = 302,
+     RDOT = 303,
+     FUNCTION = 304,
+     SUBVAL = 305,
+     ISUNAMBIGUOUS = 306,
+     ISIDENTITY = 307,
+     ISFUNCTIONAL = 308,
+     NOTID = 309,
+     LOWERUNIQ = 310,
+     LOWERUNIQEPS = 311,
+     ALLFINAL = 312,
+     UNAMBIGUOUSPART = 313,
+     AMBIGUOUSPART = 314,
+     AMBIGUOUSDOMAIN = 315,
+     EQSUBSTRINGS = 316,
+     LETTERMACHINE = 317,
+     MARKFSMTAIL = 318,
+     MARKFSMTAILLOOP = 319,
+     MARKFSMMIDLOOP = 320,
+     MARKFSMLOOP = 321,
+     ADDSINK = 322,
+     LEFTREWR = 323,
+     FLATTEN = 324,
+     SUBLABEL = 325,
+     CLOSESIGMA = 326,
+     CLOSESIGMAUNK = 327,
+     ARROW = 328,
+     DIRECTION = 329,
+     HIGH_CROSS_PRODUCT = 330,
+     CROSS_PRODUCT = 331,
+     COMPOSE = 332,
+     MINUS = 333,
+     INTERSECT = 334,
+     UNION = 335,
+     COMPLEMENT = 336,
+     INVERSE = 337,
+     REVERSE = 338,
+     KLEENE_PLUS = 339,
+     KLEENE_STAR = 340,
+     TERM_NEGATION = 341
+   };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 293 of yacc.c  */
+#line 198 "regex.y"
+
+     char *string;
+     struct fsm *net;
+     int  type;
+
+
+
+/* Line 293 of yacc.c  */
+#line 382 "regex.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 343 of yacc.c  */
+#line 407 "regex.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+  YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
+	Stack = &yyptr->Stack_alloc;					\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  105
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   1207
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  87
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  23
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  136
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  291
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   341
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    74,
+      75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
+      85,    86
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     5,     8,    11,    13,    17,    21,    25,
+      27,    29,    33,    36,    41,    43,    47,    52,    56,    59,
+      64,    70,    74,    78,    81,    87,    92,   100,   107,   115,
+     122,   128,   133,   139,   144,   148,   152,   157,   162,   168,
+     176,   183,   190,   196,   204,   211,   218,   224,   226,   230,
+     234,   238,   240,   242,   244,   248,   252,   256,   260,   264,
+     268,   272,   274,   277,   281,   285,   289,   293,   297,   299,
+     303,   307,   311,   315,   319,   321,   324,   327,   330,   333,
+     335,   337,   340,   343,   346,   349,   352,   355,   358,   362,
+     365,   368,   371,   374,   376,   379,   381,   383,   388,   391,
+     395,   399,   405,   411,   417,   420,   425,   430,   432,   436,
+     440,   444,   448,   452,   456,   460,   464,   468,   472,   476,
+     482,   488,   494,   500,   504,   510,   516,   524,   528,   532,
+     540,   544,   547,   551,   555,   559,   563
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      88,     0,    -1,    89,    -1,    89,    88,    -1,    90,     4,
+      -1,    91,    -1,    90,    77,    91,    -1,    90,    45,    91,
+      -1,    90,    76,    91,    -1,    92,    -1,    93,    -1,    92,
+      20,    92,    -1,    92,    20,    -1,    92,    20,    26,    92,
+      -1,    20,    -1,    20,    25,    92,    -1,    92,    20,    25,
+      92,    -1,    20,    26,    92,    -1,    20,    92,    -1,    20,
+      92,    26,    92,    -1,    92,    20,    92,    26,    92,    -1,
+      92,    11,    92,    -1,    92,    73,    92,    -1,    92,    73,
+      -1,    47,    92,    48,    73,    92,    -1,    47,    48,    73,
+      92,    -1,    47,    92,    48,    73,    92,    26,    92,    -1,
+      47,    48,    73,    92,    26,    92,    -1,    47,    92,    48,
+      73,    92,    74,    92,    -1,    47,    48,    73,    92,    74,
+      92,    -1,    92,    73,    92,    26,    92,    -1,    92,    73,
+      26,    92,    -1,    92,    73,    92,    74,    92,    -1,    92,
+      73,    74,    92,    -1,    92,    25,    92,    -1,    92,    73,
+      46,    -1,    92,    73,    46,    92,    -1,    92,    73,    92,
+      46,    -1,    92,    73,    92,    46,    92,    -1,    92,    73,
+      92,    46,    92,    26,    92,    -1,    92,    73,    92,    46,
+      26,    92,    -1,    92,    73,    46,    92,    26,    92,    -1,
+      92,    73,    46,    26,    92,    -1,    92,    73,    92,    46,
+      92,    74,    92,    -1,    92,    73,    46,    92,    74,    92,
+      -1,    92,    73,    92,    46,    74,    92,    -1,    92,    73,
+      46,    74,    92,    -1,    94,    -1,    93,    27,    94,    -1,
+      93,    28,    94,    -1,    93,    29,    94,    -1,    95,    -1,
+      96,    -1,    97,    -1,    96,    80,    97,    -1,    96,    43,
+      97,    -1,    96,    44,    97,    -1,    96,    79,    97,    -1,
+      96,    78,    97,    -1,    96,    37,    97,    -1,    96,    38,
+      97,    -1,    98,    -1,    97,    98,    -1,    35,    36,    97,
+      -1,    35,    39,    35,    -1,    35,    40,    35,    -1,    35,
+      28,    35,    -1,    35,    29,    35,    -1,    99,    -1,    98,
+      18,    99,    -1,    98,    19,    99,    -1,    98,    30,    99,
+      -1,    98,    31,    99,    -1,    98,    32,    99,    -1,   100,
+      -1,    81,    99,    -1,    12,    99,    -1,    14,    99,    -1,
+      13,    99,    -1,   101,    -1,   102,    -1,   101,    85,    -1,
+     101,    84,    -1,   101,    83,    -1,   101,    82,    -1,   101,
+      15,    -1,   101,    16,    -1,   101,    17,    -1,   101,    75,
+     102,    -1,   101,    21,    -1,   101,    23,    -1,   101,    24,
+      -1,   101,    22,    -1,   103,    -1,    86,   102,    -1,     3,
+      -1,   106,    -1,    33,     7,    90,     8,    -1,    34,    90,
+      -1,     7,    90,     8,    -1,     5,    90,     6,    -1,    42,
+      35,    26,    35,     8,    -1,    42,    35,    26,    90,     8,
+      -1,    42,    90,    26,    35,     8,    -1,   104,   105,    -1,
+      41,     5,    90,    26,    -1,    50,    26,    50,     6,    -1,
+     109,    -1,    52,    90,     8,    -1,    53,    90,     8,    -1,
+      51,    90,     8,    -1,    54,    90,     8,    -1,    55,    90,
+       8,    -1,    56,    90,     8,    -1,    57,    90,     8,    -1,
+      58,    90,     8,    -1,    59,    90,     8,    -1,    60,    90,
+       8,    -1,    62,    90,     8,    -1,    63,    90,    26,    90,
+       8,    -1,    64,    90,    26,    90,     8,    -1,    65,    90,
+      26,    90,     8,    -1,    66,    90,    26,    90,     8,    -1,
+      67,    90,     8,    -1,    68,    90,    26,    90,     8,    -1,
+      69,    90,    26,    90,     8,    -1,    70,    90,    26,    90,
+      26,    90,     8,    -1,    71,    90,     8,    -1,    72,    90,
+       8,    -1,    61,    90,    26,    90,    26,    90,     8,    -1,
+      49,    90,    26,    -1,    49,    90,    -1,   107,    90,    26,
+      -1,   108,    90,    26,    -1,   108,    90,     8,    -1,   107,
+      90,     8,    -1,   107,     8,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   252,   252,   253,   256,   258,   259,   260,   261,   263,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   280,   281,   282,   283,   284,   285,
+     286,   287,   288,   289,   291,   293,   294,   295,   296,   297,
+     298,   299,   300,   301,   302,   303,   304,   307,   308,   309,
+     310,   312,   314,   316,   317,   318,   319,   320,   321,   322,
+     323,   325,   326,   327,   329,   330,   331,   332,   334,   335,
+     336,   337,   338,   339,   341,   342,   343,   344,   345,   347,
+     349,   350,   351,   352,   353,   354,   355,   356,   357,   359,
+     360,   361,   362,   364,   365,   367,   368,   369,   370,   371,
+     372,   373,   374,   375,   376,   378,   379,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,   391,   392,   393,
+     394,   395,   396,   397,   398,   399,   400,   401,   402,   403,
+     405,   407,   410,   411,   413,   415,   417
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "NET", "END", "LBRACKET", "RBRACKET",
+  "LPAREN", "RPAREN", "ENDM", "ENDD", "CRESTRICT", "CONTAINS",
+  "CONTAINS_OPT_ONE", "CONTAINS_ONE", "XUPPER", "XLOWER", "FLAG_ELIMINATE",
+  "IGNORE_ALL", "IGNORE_INTERNAL", "CONTEXT", "NCONCAT", "MNCONCAT",
+  "MORENCONCAT", "LESSNCONCAT", "DOUBLE_COMMA", "COMMA", "SHUFFLE",
+  "PRECEDES", "FOLLOWS", "RIGHT_QUOTIENT", "LEFT_QUOTIENT",
+  "INTERLEAVE_QUOTIENT", "UQUANT", "EQUANT", "VAR", "IN", "IMPLIES",
+  "BICOND", "EQUALS", "NEQ", "SUBSTITUTE", "SUCCESSOR_OF",
+  "PRIORITY_UNION_U", "PRIORITY_UNION_L", "LENIENT_COMPOSE", "TRIPLE_DOT",
+  "LDOT", "RDOT", "FUNCTION", "SUBVAL", "ISUNAMBIGUOUS", "ISIDENTITY",
+  "ISFUNCTIONAL", "NOTID", "LOWERUNIQ", "LOWERUNIQEPS", "ALLFINAL",
+  "UNAMBIGUOUSPART", "AMBIGUOUSPART", "AMBIGUOUSDOMAIN", "EQSUBSTRINGS",
+  "LETTERMACHINE", "MARKFSMTAIL", "MARKFSMTAILLOOP", "MARKFSMMIDLOOP",
+  "MARKFSMLOOP", "ADDSINK", "LEFTREWR", "FLATTEN", "SUBLABEL",
+  "CLOSESIGMA", "CLOSESIGMAUNK", "ARROW", "DIRECTION",
+  "HIGH_CROSS_PRODUCT", "CROSS_PRODUCT", "COMPOSE", "MINUS", "INTERSECT",
+  "UNION", "COMPLEMENT", "INVERSE", "REVERSE", "KLEENE_PLUS",
+  "KLEENE_STAR", "TERM_NEGATION", "$accept", "start", "regex", "network",
+  "networkA", "n0", "network1", "network2", "network3", "network4",
+  "network5", "network6", "network7", "network8", "network9", "network10",
+  "network11", "sub1", "sub2", "network12", "fstart", "fmid", "fend", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
+     315,   316,   317,   318,   319,   320,   321,   322,   323,   324,
+     325,   326,   327,   328,   329,   330,   331,   332,   333,   334,
+     335,   336,   337,   338,   339,   340,   341
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    87,    88,    88,    89,    90,    90,    90,    90,    91,
+      92,    92,    92,    92,    92,    92,    92,    92,    92,    92,
+      92,    92,    92,    92,    92,    92,    92,    92,    92,    92,
+      92,    92,    92,    92,    92,    92,    92,    92,    92,    92,
+      92,    92,    92,    92,    92,    92,    92,    93,    93,    93,
+      93,    94,    95,    96,    96,    96,    96,    96,    96,    96,
+      96,    97,    97,    97,    97,    97,    97,    97,    98,    98,
+      98,    98,    98,    98,    99,    99,    99,    99,    99,   100,
+     101,   101,   101,   101,   101,   101,   101,   101,   101,   101,
+     101,   101,   101,   102,   102,   103,   103,   103,   103,   103,
+     103,   103,   103,   103,   103,   104,   105,   106,   106,   106,
+     106,   106,   106,   106,   106,   106,   106,   106,   106,   106,
+     106,   106,   106,   106,   106,   106,   106,   106,   106,   106,
+     107,   107,   108,   108,   109,   109,   109
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     2,     2,     1,     3,     3,     3,     1,
+       1,     3,     2,     4,     1,     3,     4,     3,     2,     4,
+       5,     3,     3,     2,     5,     4,     7,     6,     7,     6,
+       5,     4,     5,     4,     3,     3,     4,     4,     5,     7,
+       6,     6,     5,     7,     6,     6,     5,     1,     3,     3,
+       3,     1,     1,     1,     3,     3,     3,     3,     3,     3,
+       3,     1,     2,     3,     3,     3,     3,     3,     1,     3,
+       3,     3,     3,     3,     1,     2,     2,     2,     2,     1,
+       1,     2,     2,     2,     2,     2,     2,     2,     3,     2,
+       2,     2,     2,     1,     2,     1,     1,     4,     2,     3,
+       3,     5,     5,     5,     2,     4,     4,     1,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     5,
+       5,     5,     5,     3,     5,     5,     7,     3,     3,     7,
+       3,     2,     3,     3,     3,     3,     2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       0,    95,     0,     0,     0,     0,     0,    14,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       2,     0,     5,     9,    10,    47,    51,    52,    53,    61,
+      68,    74,    79,    80,    93,     0,    96,     0,     0,   107,
+       0,     0,    76,    78,    77,     0,     0,    18,     0,    98,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     131,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    75,    94,     1,     3,     4,     0,     0,
+       0,     0,    12,     0,    23,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,    62,     0,     0,     0,     0,
+       0,    85,    86,    87,    89,    92,    90,    91,     0,    84,
+      83,    82,    81,     0,   104,   136,     0,     0,   100,    99,
+      15,    17,     0,     0,    66,    67,    63,    64,    65,     0,
+       0,     0,     0,     0,   130,   110,   108,   109,   111,   112,
+     113,   114,   115,   116,   117,     0,   118,     0,     0,     0,
+       0,   123,     0,     0,     0,   127,   128,     7,     8,     6,
+      21,     0,     0,    11,    34,     0,    35,     0,    22,    48,
+      49,    50,    59,    60,    55,    56,    58,    57,    54,    69,
+      70,    71,    72,    73,    88,     0,   135,   132,   134,   133,
+      19,    97,   105,     0,     0,     0,    25,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    16,    13,     0,    31,
+       0,     0,    36,    33,     0,    37,     0,     0,   101,   102,
+     103,     0,     0,    24,     0,   119,   120,   121,   122,   124,
+     125,     0,    20,    42,    46,     0,     0,    30,     0,     0,
+      38,    32,   106,    27,    29,     0,     0,     0,     0,    41,
+      44,    40,    45,     0,     0,    26,    28,   129,   126,    39,
+      43
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,   144,    56,
+      57,    58,    59
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -42
+static const yytype_int16 yypact[] =
+{
+     750,   -42,   750,   750,    68,    68,    68,   330,     2,   750,
+     207,     5,   820,   610,   750,   750,   750,   750,   750,   750,
+     750,   750,   750,   750,   750,   750,   750,   750,   750,   750,
+     750,   750,   750,   750,   750,   750,   750,    68,  1001,    12,
+     750,     0,   -42,   133,    60,   -42,   -42,  1127,    68,   413,
+     -42,   -42,   200,   -42,   -42,   -12,   -42,   680,   750,   -42,
+      66,   142,   -42,   -42,   -42,   750,   750,    43,   750,   -40,
+       8,     9,   960,    15,    20,   750,    13,   333,   -33,  1090,
+     403,   152,   263,   291,   361,   431,   501,   571,   641,   711,
+     781,   473,   851,   543,   683,   753,   823,   921,  1057,  1066,
+    1069,   962,  1002,   -42,   -42,   -42,   -42,   -42,   750,   750,
+     750,   750,   400,   750,   260,   960,   960,   960,   960,   960,
+     960,   960,   960,   960,   960,   413,    68,    68,    68,    68,
+      68,   -42,   -42,   -42,   -42,   -42,   -42,   -42,  1001,   -42,
+     -42,   -42,   -42,    35,   -42,   -42,   149,   165,   -42,   -42,
+     133,   133,   750,  1029,   -42,   -42,    68,   -42,   -42,  1073,
+     890,    27,   750,    -9,   -42,   -42,   -42,   -42,   -42,   -42,
+     -42,   -42,   -42,   -42,   -42,   750,   -42,   750,   750,   750,
+     750,   -42,   750,   750,   750,   -42,   -42,   -42,   -42,   -42,
+     133,   750,   750,   350,   133,   750,   470,   750,    40,   -42,
+     -42,   -42,    68,    68,    68,    68,    68,    68,    68,   -42,
+     -42,   -42,   -42,   -42,   -42,    28,   -42,   -42,   -42,   -42,
+     133,   -42,   -42,  1158,  1032,    62,    73,   750,  1096,  1036,
+    1040,  1043,  1076,  1078,  1081,  1099,   133,   133,   750,   133,
+     750,   750,   175,   133,   750,   540,   750,    77,   -42,   -42,
+     -42,   750,   750,   182,   750,   -42,   -42,   -42,   -42,   -42,
+     -42,   750,   133,   133,   133,   750,   750,   133,   750,   750,
+     278,   133,   -42,   133,   133,   750,   750,  1083,  1085,   133,
+     133,   133,   133,   750,   750,   133,   133,   -42,   -42,   133,
+     133
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -42,    45,   -42,    -1,   -18,    -7,   -42,   -21,   -42,   -42,
+     513,   -41,    42,   -42,   -42,   -35,   -42,   -42,   -42,   -42,
+     -42,   -42,   -42
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+      67,    60,    61,   104,   107,   108,    79,   125,    69,    68,
+      75,    77,   105,    80,    81,    82,    83,    84,    85,    86,
+      87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   109,   110,   143,   160,
+     162,    70,    71,   154,   155,   108,    62,    63,    64,    72,
+     157,   111,    73,    74,   111,   158,   146,   147,   150,   151,
+     112,   215,   225,   112,   227,   113,   244,   153,   113,   152,
+     250,     1,   148,     2,   159,     3,   109,   110,   247,   103,
+       4,     5,     6,   272,   111,   106,   245,   115,   116,   117,
+     187,   188,   189,   112,   199,   200,   201,     0,   113,   251,
+       0,     8,     9,   214,   190,   193,   194,   198,     0,    11,
+      12,   108,     0,   114,   246,   125,   114,    14,     0,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,     0,   109,   110,   111,   220,   114,   252,     0,    37,
+     149,     0,     0,   112,    38,   226,     0,   216,   113,   224,
+     165,   125,   125,   125,   125,   125,   125,   125,   209,   210,
+     211,   212,   213,   218,   228,   217,   229,   230,   231,   232,
+       0,   233,   234,   235,   236,   237,   111,   108,   239,   242,
+     243,   219,     0,   111,   108,   112,     0,   108,     0,     0,
+     113,   265,   112,     0,     0,     0,   114,   113,   275,     0,
+     108,     0,     0,     0,     0,   131,   132,   133,   109,   110,
+     253,   134,   135,   136,   137,   109,   110,     0,   109,   110,
+       0,   262,     0,   263,   264,    70,    71,   267,   270,   271,
+       0,   109,   110,    72,   273,   274,    73,    74,   114,   266,
+       0,     0,     0,   277,     0,   114,   276,     0,   279,   280,
+     278,   281,   282,     1,     0,     2,     0,     3,   285,   286,
+       0,   166,     4,     5,     6,   138,   289,   290,     0,     0,
+       7,     0,   139,   140,   141,   142,   195,     0,     0,   111,
+       0,     0,     0,     8,     9,    10,     0,     0,   112,   167,
+       0,    11,    12,   113,   283,     0,   196,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,   197,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,   114,   284,     0,     0,    65,    66,     0,     0,   161,
+       0,   111,     0,     8,     9,    10,     0,   109,   110,   168,
+     112,    11,    12,     0,     0,   113,   238,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,   114,     0,   191,   192,     0,     0,   164,
+       0,   126,   127,     8,     9,    10,     0,   109,   110,   169,
+       0,    11,    12,   128,   129,   130,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,   240,     0,     0,   175,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,   170,
+       0,    11,    12,     0,     0,     0,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,   241,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,   268,     0,     0,   177,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,   171,
+       0,    11,    12,     0,     0,   156,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,   269,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,   202,   203,   204,   205,   206,   207,   208,     0,     0,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,   172,
+       0,    11,    12,     0,     0,     0,     0,    13,    78,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,   145,     0,
+       0,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,     0,     0,     0,   178,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,   173,
+       0,    11,    12,     0,     0,     0,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,     0,     0,     0,   179,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,   174,
+       0,    11,    12,     0,     0,     0,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,     0,     0,     0,   180,
+       0,     0,     0,     8,     9,    76,     0,   109,   110,   176,
+       0,    11,    12,     0,     0,     0,     0,    13,   108,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,   109,
+     110,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       7,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     8,     9,   223,     0,   109,   110,   181,
+       0,    11,    12,     0,     0,     0,     0,    13,     0,    14,
+       0,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     1,     0,     2,   108,     3,     0,     0,
+     185,    37,     4,     5,     6,     0,    38,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     8,     9,    10,     0,   109,   110,     0,
+       0,    11,    12,     0,     1,     0,     2,   108,     3,    14,
+     186,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,     0,     8,     9,     0,   221,   109,   110,
+     249,    37,    11,    12,   255,     0,    38,   108,   256,     0,
+      14,   257,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,   108,     0,     0,   108,   109,   110,
+       0,   108,     0,   182,   258,   108,   259,    38,   108,   260,
+       0,   287,   183,   288,     0,   184,     0,     0,     0,   222,
+       0,   111,   108,     0,     0,   109,   110,     0,   109,   110,
+     112,   108,   109,   110,   108,   113,   109,   110,   108,   109,
+     110,   108,   254,   108,     0,   261,   108,     0,   108,     0,
+     108,     0,     0,   109,   110,     0,     0,     0,   163,     0,
+       0,   108,   109,   110,   108,   109,   110,     0,     0,   109,
+     110,     0,   109,   110,   109,   110,     0,   109,   110,   109,
+     110,   109,   110,   114,   118,   119,   248,     0,     0,     0,
+     120,   121,   109,   110,     0,   109,   110,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    70,    71,     0,     0,
+       0,     0,     0,     0,    72,     0,     0,    73,    74,     0,
+       0,     0,     0,     0,     0,   122,   123,   124
+};
+
+#define yypact_value_is_default(yystate) \
+  ((yystate) == (-42))
+
+#define yytable_value_is_error(yytable_value) \
+  YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+       7,     2,     3,    38,     4,    45,    13,    48,     9,     7,
+       5,    12,     0,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    76,    77,    50,    26,
+      73,    28,    29,    35,    35,    45,     4,     5,     6,    36,
+      35,    11,    39,    40,    11,    35,    57,    58,    65,    66,
+      20,    26,    35,    20,    73,    25,    26,    68,    25,    26,
+       8,     3,     6,     5,    75,     7,    76,    77,    50,    37,
+      12,    13,    14,     6,    11,    40,    46,    27,    28,    29,
+     108,   109,   110,    20,   115,   116,   117,    -1,    25,    26,
+      -1,    33,    34,   138,   111,   112,   113,   114,    -1,    41,
+      42,    45,    -1,    73,    74,   156,    73,    49,    -1,    51,
+      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+      62,    63,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    -1,    76,    77,    11,   152,    73,    74,    -1,    81,
+       8,    -1,    -1,    20,    86,   162,    -1,     8,    25,   160,
+       8,   202,   203,   204,   205,   206,   207,   208,   126,   127,
+     128,   129,   130,     8,   175,    26,   177,   178,   179,   180,
+      -1,   182,   183,   184,   191,   192,    11,    45,   195,   196,
+     197,    26,    -1,    11,    45,    20,    -1,    45,    -1,    -1,
+      25,    26,    20,    -1,    -1,    -1,    73,    25,    26,    -1,
+      45,    -1,    -1,    -1,    -1,    15,    16,    17,    76,    77,
+     227,    21,    22,    23,    24,    76,    77,    -1,    76,    77,
+      -1,   238,    -1,   240,   241,    28,    29,   244,   245,   246,
+      -1,    76,    77,    36,   251,   252,    39,    40,    73,    74,
+      -1,    -1,    -1,   254,    -1,    73,    74,    -1,   265,   266,
+     261,   268,   269,     3,    -1,     5,    -1,     7,   275,   276,
+      -1,     8,    12,    13,    14,    75,   283,   284,    -1,    -1,
+      20,    -1,    82,    83,    84,    85,    26,    -1,    -1,    11,
+      -1,    -1,    -1,    33,    34,    35,    -1,    -1,    20,     8,
+      -1,    41,    42,    25,    26,    -1,    46,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    74,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    73,    74,    -1,    -1,    25,    26,    -1,    -1,    26,
+      -1,    11,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      20,    41,    42,    -1,    -1,    25,    26,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    73,    -1,    25,    26,    -1,    -1,    26,
+      -1,    18,    19,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    30,    31,    32,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    26,    -1,    -1,    26,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    74,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    26,    -1,    -1,    26,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    72,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    74,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,   118,   119,   120,   121,   122,   123,   124,    -1,    -1,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    48,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,     8,    -1,
+      -1,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    26,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    26,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    26,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    45,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    76,
+      77,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      20,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,     8,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    47,    -1,    49,
+      -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,     3,    -1,     5,    45,     7,    -1,    -1,
+       8,    81,    12,    13,    14,    -1,    86,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    33,    34,    35,    -1,    76,    77,    -1,
+      -1,    41,    42,    -1,     3,    -1,     5,    45,     7,    49,
+       8,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    -1,    33,    34,    -1,     8,    76,    77,
+       8,    81,    41,    42,     8,    -1,    86,    45,     8,    -1,
+      49,     8,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    45,    -1,    -1,    45,    76,    77,
+      -1,    45,    -1,    26,     8,    45,     8,    86,    45,     8,
+      -1,     8,    26,     8,    -1,    26,    -1,    -1,    -1,    26,
+      -1,    11,    45,    -1,    -1,    76,    77,    -1,    76,    77,
+      20,    45,    76,    77,    45,    25,    76,    77,    45,    76,
+      77,    45,    26,    45,    -1,    26,    45,    -1,    45,    -1,
+      45,    -1,    -1,    76,    77,    -1,    -1,    -1,    48,    -1,
+      -1,    45,    76,    77,    45,    76,    77,    -1,    -1,    76,
+      77,    -1,    76,    77,    76,    77,    -1,    76,    77,    76,
+      77,    76,    77,    73,    37,    38,     8,    -1,    -1,    -1,
+      43,    44,    76,    77,    -1,    76,    77,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    28,    29,    -1,    -1,
+      -1,    -1,    -1,    -1,    36,    -1,    -1,    39,    40,    -1,
+      -1,    -1,    -1,    -1,    -1,    78,    79,    80
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,     5,     7,    12,    13,    14,    20,    33,    34,
+      35,    41,    42,    47,    49,    51,    52,    53,    54,    55,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    81,    86,    88,
+      89,    90,    91,    92,    93,    94,    95,    96,    97,    98,
+      99,   100,   101,   102,   103,   104,   106,   107,   108,   109,
+      90,    90,    99,    99,    99,    25,    26,    92,     7,    90,
+      28,    29,    36,    39,    40,     5,    35,    90,    48,    92,
+      90,    90,    90,    90,    90,    90,    90,    90,    90,    90,
+      90,    90,    90,    90,    90,    90,    90,    90,    90,    90,
+      90,    90,    90,    99,   102,     0,    88,     4,    45,    76,
+      77,    11,    20,    25,    73,    27,    28,    29,    37,    38,
+      43,    44,    78,    79,    80,    98,    18,    19,    30,    31,
+      32,    15,    16,    17,    21,    22,    23,    24,    75,    82,
+      83,    84,    85,    50,   105,     8,    90,    90,     6,     8,
+      92,    92,    26,    90,    35,    35,    97,    35,    35,    90,
+      26,    26,    73,    48,    26,     8,     8,     8,     8,     8,
+       8,     8,     8,     8,     8,    26,     8,    26,    26,    26,
+      26,     8,    26,    26,    26,     8,     8,    91,    91,    91,
+      92,    25,    26,    92,    92,    26,    46,    74,    92,    94,
+      94,    94,    97,    97,    97,    97,    97,    97,    97,    99,
+      99,    99,    99,    99,   102,    26,     8,    26,     8,    26,
+      92,     8,    26,    35,    90,    35,    92,    73,    90,    90,
+      90,    90,    90,    90,    90,    90,    92,    92,    26,    92,
+      26,    74,    92,    92,    26,    46,    74,    50,     8,     8,
+       8,    26,    74,    92,    26,     8,     8,     8,     8,     8,
+       8,    26,    92,    92,    92,    26,    74,    92,    26,    74,
+      92,    92,     6,    92,    92,    26,    74,    90,    90,    92,
+      92,    92,    92,    26,    74,    92,    92,     8,     8,    92,
+      92
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  However,
+   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
+   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+   discussed.  */
+
+#define YYFAIL		goto yyerrlab
+#if defined YYFAIL
+  /* This is here to suppress warnings from the GCC cpp's
+     -Wunused-macros.  Normally we don't worry about that warning, but
+     some users do, and we want to make it easy for users to remove
+     YYFAIL uses, which will produce warnings from Bison 2.5.  */
+#endif
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      //yyerror (&yylloc, scanner, defined_nets, defined_funcs, YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (YYID (N))                                                    \
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+	      (Loc).first_line, (Loc).first_column,	\
+	      (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+typedef void* yyscan_t;
+extern int yylex(YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value, Location, scanner, defined_nets, defined_funcs); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner, defined_nets, defined_funcs)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    void *scanner;
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (yylocationp);
+  YYUSE (scanner);
+  YYUSE (defined_nets);
+  YYUSE (defined_funcs);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner, defined_nets, defined_funcs)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
+    void *scanner;
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner, defined_nets, defined_funcs);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, scanner, defined_nets, defined_funcs)
+    YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
+    int yyrule;
+    void *scanner;
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       , &(yylsp[(yyi + 1) - (yynrhs)])		       , scanner, defined_nets, defined_funcs);
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, yylsp, Rule, scanner, defined_nets, defined_funcs); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  YYSIZE_T yysize1;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = 0;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
+    {
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                if (! (yysize <= yysize1
+                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                  return 2;
+                yysize = yysize1;
+              }
+        }
+    }
+
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
+
+  yysize1 = yysize + yystrlen (yyformat);
+  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+    return 2;
+  yysize = yysize1;
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
+    }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, scanner, defined_nets, defined_funcs)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
+    void *scanner;
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (yylocationp);
+  YYUSE (scanner);
+  YYUSE (defined_nets);
+  YYUSE (defined_funcs);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *scanner, struct defined_networks *defined_nets, struct defined_functions *defined_funcs)
+#else
+int
+yyparse (scanner, defined_nets, defined_funcs)
+    void *scanner;
+    struct defined_networks *defined_nets;
+    struct defined_functions *defined_funcs;
+#endif
+#endif
+{
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Location data for the lookahead symbol.  */
+YYLTYPE yylloc;
+
+    /* Number of syntax errors so far.  */
+    int yynerrs;
+
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
+       `yyls': related to locations.
+
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    /* The location stack.  */
+    YYLTYPE yylsa[YYINITDEPTH];
+    YYLTYPE *yyls;
+    YYLTYPE *yylsp;
+
+    /* The locations where the error started and ended.  */
+    YYLTYPE yyerror_range[3];
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+  YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yyls = yylsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+  yyssp = yyss;
+  yyvsp = yyvs;
+  yylsp = yyls;
+
+#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  /* Initialize the default location before parsing starts.  */
+  yylloc.first_line   = yylloc.last_line   = 1;
+  yylloc.first_column = yylloc.last_column = 1;
+#endif
+
+/* User initialization code.  */
+
+/* Line 1590 of yacc.c  */
+#line 211 "regex.y"
+{
+    clear_quantifiers();
+    rewrite = 0;
+    contexts = NULL;
+    rules = NULL;
+    rewrite_rules = NULL;
+    rule_direction = 0;
+    substituting = 0;
+}
+
+/* Line 1590 of yacc.c  */
+#line 1986 "regex.c"
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	yytype_int16 *yyss1 = yyss;
+	YYLTYPE *yyls1 = yyls;
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yyls1, yysize * sizeof (*yylsp),
+		    &yystacksize);
+
+	yyls = yyls1;
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+	YYSTACK_RELOCATE (yyls_alloc, yyls);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+  *++yylsp = yylloc;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+
+/* Line 1806 of yacc.c  */
+#line 256 "regex.y"
+    { current_parse = (yyvsp[(1) - (2)].net);              }
+    break;
+
+  case 5:
+
+/* Line 1806 of yacc.c  */
+#line 258 "regex.y"
+    { }
+    break;
+
+  case 6:
+
+/* Line 1806 of yacc.c  */
+#line 259 "regex.y"
+    { (yyval.net) = fsm_compose((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));         }
+    break;
+
+  case 7:
+
+/* Line 1806 of yacc.c  */
+#line 260 "regex.y"
+    { (yyval.net) = fsm_lenient_compose((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net)); }
+    break;
+
+  case 8:
+
+/* Line 1806 of yacc.c  */
+#line 261 "regex.y"
+    { (yyval.net) = fsm_cross_product((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));   }
+    break;
+
+  case 9:
+
+/* Line 1806 of yacc.c  */
+#line 263 "regex.y"
+    { if (rewrite) { add_rewrite_rule(); (yyval.net) = fsm_rewrite(rewrite_rules); clear_rewrite_ruleset(rewrite_rules); } rewrite = 0; contexts = NULL; rules = NULL; rewrite_rules = NULL; }
+    break;
+
+  case 10:
+
+/* Line 1806 of yacc.c  */
+#line 265 "regex.y"
+    { }
+    break;
+
+  case 11:
+
+/* Line 1806 of yacc.c  */
+#line 266 "regex.y"
+    { (yyval.net) = NULL; add_context_pair((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));}
+    break;
+
+  case 12:
+
+/* Line 1806 of yacc.c  */
+#line 267 "regex.y"
+    { add_context_pair((yyvsp[(1) - (2)].net),fsm_empty_string()); }
+    break;
+
+  case 13:
+
+/* Line 1806 of yacc.c  */
+#line 268 "regex.y"
+    { add_context_pair((yyvsp[(1) - (4)].net),fsm_empty_string()); }
+    break;
+
+  case 14:
+
+/* Line 1806 of yacc.c  */
+#line 269 "regex.y"
+    { add_context_pair(fsm_empty_string(),fsm_empty_string());}
+    break;
+
+  case 15:
+
+/* Line 1806 of yacc.c  */
+#line 270 "regex.y"
+    { add_rewrite_rule(); add_context_pair(fsm_empty_string(),fsm_empty_string());}
+    break;
+
+  case 16:
+
+/* Line 1806 of yacc.c  */
+#line 271 "regex.y"
+    { add_rewrite_rule(); add_context_pair((yyvsp[(1) - (4)].net),fsm_empty_string());}
+    break;
+
+  case 17:
+
+/* Line 1806 of yacc.c  */
+#line 272 "regex.y"
+    { add_context_pair(fsm_empty_string(),fsm_empty_string());}
+    break;
+
+  case 18:
+
+/* Line 1806 of yacc.c  */
+#line 273 "regex.y"
+    { add_context_pair(fsm_empty_string(),(yyvsp[(2) - (2)].net)); }
+    break;
+
+  case 19:
+
+/* Line 1806 of yacc.c  */
+#line 274 "regex.y"
+    { add_context_pair(fsm_empty_string(),(yyvsp[(2) - (4)].net)); }
+    break;
+
+  case 20:
+
+/* Line 1806 of yacc.c  */
+#line 275 "regex.y"
+    { add_context_pair((yyvsp[(1) - (5)].net),(yyvsp[(3) - (5)].net)); }
+    break;
+
+  case 21:
+
+/* Line 1806 of yacc.c  */
+#line 276 "regex.y"
+    { (yyval.net) = fsm_context_restrict((yyvsp[(1) - (3)].net),contexts); fsm_clear_contexts(contexts);}
+    break;
+
+  case 22:
+
+/* Line 1806 of yacc.c  */
+#line 277 "regex.y"
+    { add_rule((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net),NULL,(yyvsp[(2) - (3)].type)); if ((yyvsp[(1) - (3)].net)->arity == 2) { printf("Error: LHS is transducer\n"); YYERROR;}}
+    break;
+
+  case 23:
+
+/* Line 1806 of yacc.c  */
+#line 278 "regex.y"
+    { add_rule((yyvsp[(1) - (2)].net),NULL,NULL,(yyvsp[(2) - (2)].type)); }
+    break;
+
+  case 24:
+
+/* Line 1806 of yacc.c  */
+#line 280 "regex.y"
+    { add_rule((yyvsp[(2) - (5)].net),(yyvsp[(5) - (5)].net),NULL,(yyvsp[(4) - (5)].type)|ARROW_DOTTED); if ((yyvsp[(5) - (5)].net) == NULL) { YYERROR;}}
+    break;
+
+  case 25:
+
+/* Line 1806 of yacc.c  */
+#line 281 "regex.y"
+    { add_eprule((yyvsp[(4) - (4)].net),NULL,(yyvsp[(3) - (4)].type)|ARROW_DOTTED); if ((yyvsp[(4) - (4)].net) == NULL) { YYERROR;}}
+    break;
+
+  case 26:
+
+/* Line 1806 of yacc.c  */
+#line 282 "regex.y"
+    { add_rule((yyvsp[(2) - (7)].net),(yyvsp[(5) - (7)].net),NULL,(yyvsp[(4) - (7)].type)|ARROW_DOTTED);}
+    break;
+
+  case 27:
+
+/* Line 1806 of yacc.c  */
+#line 283 "regex.y"
+    { add_eprule((yyvsp[(4) - (6)].net),NULL,(yyvsp[(3) - (6)].type)|ARROW_DOTTED);}
+    break;
+
+  case 28:
+
+/* Line 1806 of yacc.c  */
+#line 284 "regex.y"
+    { add_rule((yyvsp[(2) - (7)].net),(yyvsp[(5) - (7)].net),NULL,(yyvsp[(4) - (7)].type)|ARROW_DOTTED); rule_direction = (yyvsp[(6) - (7)].type);}
+    break;
+
+  case 29:
+
+/* Line 1806 of yacc.c  */
+#line 285 "regex.y"
+    { add_eprule((yyvsp[(4) - (6)].net),NULL,(yyvsp[(3) - (6)].type)|ARROW_DOTTED); rule_direction = (yyvsp[(5) - (6)].type);}
+    break;
+
+  case 30:
+
+/* Line 1806 of yacc.c  */
+#line 286 "regex.y"
+    { add_rule((yyvsp[(1) - (5)].net),(yyvsp[(3) - (5)].net),NULL,(yyvsp[(2) - (5)].type));}
+    break;
+
+  case 31:
+
+/* Line 1806 of yacc.c  */
+#line 287 "regex.y"
+    { add_rule((yyvsp[(1) - (4)].net),NULL,NULL,(yyvsp[(2) - (4)].type));}
+    break;
+
+  case 32:
+
+/* Line 1806 of yacc.c  */
+#line 288 "regex.y"
+    { add_rule((yyvsp[(1) - (5)].net),(yyvsp[(3) - (5)].net),NULL,(yyvsp[(2) - (5)].type)); rule_direction = (yyvsp[(4) - (5)].type);}
+    break;
+
+  case 33:
+
+/* Line 1806 of yacc.c  */
+#line 289 "regex.y"
+    { add_rule((yyvsp[(1) - (4)].net),NULL,NULL,(yyvsp[(2) - (4)].type)); rule_direction = (yyvsp[(3) - (4)].type);}
+    break;
+
+  case 34:
+
+/* Line 1806 of yacc.c  */
+#line 291 "regex.y"
+    { add_rewrite_rule();}
+    break;
+
+  case 35:
+
+/* Line 1806 of yacc.c  */
+#line 293 "regex.y"
+    { add_rule((yyvsp[(1) - (3)].net),fsm_empty_string(),fsm_empty_string(),(yyvsp[(2) - (3)].type));}
+    break;
+
+  case 36:
+
+/* Line 1806 of yacc.c  */
+#line 294 "regex.y"
+    { add_rule((yyvsp[(1) - (4)].net),fsm_empty_string(),(yyvsp[(4) - (4)].net),(yyvsp[(2) - (4)].type));}
+    break;
+
+  case 37:
+
+/* Line 1806 of yacc.c  */
+#line 295 "regex.y"
+    { add_rule((yyvsp[(1) - (4)].net),(yyvsp[(3) - (4)].net),fsm_empty_string(),(yyvsp[(2) - (4)].type));}
+    break;
+
+  case 38:
+
+/* Line 1806 of yacc.c  */
+#line 296 "regex.y"
+    { add_rule((yyvsp[(1) - (5)].net),(yyvsp[(3) - (5)].net),(yyvsp[(5) - (5)].net),(yyvsp[(2) - (5)].type));}
+    break;
+
+  case 39:
+
+/* Line 1806 of yacc.c  */
+#line 297 "regex.y"
+    { add_rule((yyvsp[(1) - (7)].net),(yyvsp[(3) - (7)].net),(yyvsp[(5) - (7)].net),(yyvsp[(2) - (7)].type));}
+    break;
+
+  case 40:
+
+/* Line 1806 of yacc.c  */
+#line 298 "regex.y"
+    { add_rule((yyvsp[(1) - (6)].net),(yyvsp[(3) - (6)].net),fsm_empty_string(),(yyvsp[(2) - (6)].type));}
+    break;
+
+  case 41:
+
+/* Line 1806 of yacc.c  */
+#line 299 "regex.y"
+    { add_rule((yyvsp[(1) - (6)].net),fsm_empty_string(),(yyvsp[(4) - (6)].net),(yyvsp[(2) - (6)].type));}
+    break;
+
+  case 42:
+
+/* Line 1806 of yacc.c  */
+#line 300 "regex.y"
+    { add_rule((yyvsp[(1) - (5)].net),fsm_empty_string(),fsm_empty_string(),(yyvsp[(2) - (5)].type));}
+    break;
+
+  case 43:
+
+/* Line 1806 of yacc.c  */
+#line 301 "regex.y"
+    { add_rule((yyvsp[(1) - (7)].net),(yyvsp[(3) - (7)].net),(yyvsp[(5) - (7)].net),(yyvsp[(2) - (7)].type)); rule_direction = (yyvsp[(6) - (7)].type);}
+    break;
+
+  case 44:
+
+/* Line 1806 of yacc.c  */
+#line 302 "regex.y"
+    { add_rule((yyvsp[(1) - (6)].net),fsm_empty_string(),(yyvsp[(4) - (6)].net),(yyvsp[(2) - (6)].type)); rule_direction = (yyvsp[(5) - (6)].type);}
+    break;
+
+  case 45:
+
+/* Line 1806 of yacc.c  */
+#line 303 "regex.y"
+    { add_rule((yyvsp[(1) - (6)].net),(yyvsp[(3) - (6)].net),fsm_empty_string(),(yyvsp[(2) - (6)].type)); rule_direction = (yyvsp[(5) - (6)].type);}
+    break;
+
+  case 46:
+
+/* Line 1806 of yacc.c  */
+#line 304 "regex.y"
+    { add_rule((yyvsp[(1) - (5)].net),fsm_empty_string(),fsm_empty_string(),(yyvsp[(2) - (5)].type)); rule_direction = (yyvsp[(4) - (5)].type);}
+    break;
+
+  case 47:
+
+/* Line 1806 of yacc.c  */
+#line 307 "regex.y"
+    { }
+    break;
+
+  case 48:
+
+/* Line 1806 of yacc.c  */
+#line 308 "regex.y"
+    { (yyval.net) = fsm_shuffle((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));  }
+    break;
+
+  case 49:
+
+/* Line 1806 of yacc.c  */
+#line 309 "regex.y"
+    { (yyval.net) = fsm_precedes((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net)); }
+    break;
+
+  case 50:
+
+/* Line 1806 of yacc.c  */
+#line 310 "regex.y"
+    { (yyval.net) = fsm_follows((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));  }
+    break;
+
+  case 51:
+
+/* Line 1806 of yacc.c  */
+#line 312 "regex.y"
+    { }
+    break;
+
+  case 52:
+
+/* Line 1806 of yacc.c  */
+#line 314 "regex.y"
+    { }
+    break;
+
+  case 53:
+
+/* Line 1806 of yacc.c  */
+#line 316 "regex.y"
+    { }
+    break;
+
+  case 54:
+
+/* Line 1806 of yacc.c  */
+#line 317 "regex.y"
+    { (yyval.net) = fsm_union((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));                     }
+    break;
+
+  case 55:
+
+/* Line 1806 of yacc.c  */
+#line 318 "regex.y"
+    { (yyval.net) = fsm_priority_union_upper((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));      }
+    break;
+
+  case 56:
+
+/* Line 1806 of yacc.c  */
+#line 319 "regex.y"
+    { (yyval.net) = fsm_priority_union_lower((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));      }
+    break;
+
+  case 57:
+
+/* Line 1806 of yacc.c  */
+#line 320 "regex.y"
+    { (yyval.net) = fsm_intersect((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));                 }
+    break;
+
+  case 58:
+
+/* Line 1806 of yacc.c  */
+#line 321 "regex.y"
+    { (yyval.net) = fsm_minus((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));                     }
+    break;
+
+  case 59:
+
+/* Line 1806 of yacc.c  */
+#line 322 "regex.y"
+    { (yyval.net) = fsm_union(fsm_complement((yyvsp[(1) - (3)].net)),(yyvsp[(3) - (3)].net));     }
+    break;
+
+  case 60:
+
+/* Line 1806 of yacc.c  */
+#line 323 "regex.y"
+    { (yyval.net) = fsm_intersect(fsm_union(fsm_complement(fsm_copy((yyvsp[(1) - (3)].net))),fsm_copy((yyvsp[(3) - (3)].net))), fsm_union(fsm_complement(fsm_copy((yyvsp[(3) - (3)].net))),fsm_copy((yyvsp[(1) - (3)].net)))); fsm_destroy((yyvsp[(1) - (3)].net)); fsm_destroy((yyvsp[(3) - (3)].net));}
+    break;
+
+  case 61:
+
+/* Line 1806 of yacc.c  */
+#line 325 "regex.y"
+    { }
+    break;
+
+  case 62:
+
+/* Line 1806 of yacc.c  */
+#line 326 "regex.y"
+    { (yyval.net) = fsm_concat((yyvsp[(1) - (2)].net),(yyvsp[(2) - (2)].net)); }
+    break;
+
+  case 63:
+
+/* Line 1806 of yacc.c  */
+#line 327 "regex.y"
+    { (yyval.net) = fsm_ignore(fsm_contains(fsm_concat(fsm_symbol((yyvsp[(1) - (3)].string)),fsm_concat((yyvsp[(3) - (3)].net),fsm_symbol((yyvsp[(1) - (3)].string))))),union_quantifiers(),OP_IGNORE_ALL); }
+    break;
+
+  case 64:
+
+/* Line 1806 of yacc.c  */
+#line 329 "regex.y"
+    { (yyval.net) = fsm_logical_eq((yyvsp[(1) - (3)].string),(yyvsp[(3) - (3)].string)); }
+    break;
+
+  case 65:
+
+/* Line 1806 of yacc.c  */
+#line 330 "regex.y"
+    { (yyval.net) = fsm_complement(fsm_logical_eq((yyvsp[(1) - (3)].string),(yyvsp[(3) - (3)].string))); }
+    break;
+
+  case 66:
+
+/* Line 1806 of yacc.c  */
+#line 331 "regex.y"
+    { (yyval.net) = fsm_logical_precedence((yyvsp[(1) - (3)].string),(yyvsp[(3) - (3)].string)); }
+    break;
+
+  case 67:
+
+/* Line 1806 of yacc.c  */
+#line 332 "regex.y"
+    { (yyval.net) = fsm_logical_precedence((yyvsp[(3) - (3)].string),(yyvsp[(1) - (3)].string)); }
+    break;
+
+  case 68:
+
+/* Line 1806 of yacc.c  */
+#line 334 "regex.y"
+    { }
+    break;
+
+  case 69:
+
+/* Line 1806 of yacc.c  */
+#line 335 "regex.y"
+    { (yyval.net) = fsm_ignore((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net), OP_IGNORE_ALL);          }
+    break;
+
+  case 70:
+
+/* Line 1806 of yacc.c  */
+#line 336 "regex.y"
+    { (yyval.net) = fsm_ignore((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net), OP_IGNORE_INTERNAL);     }
+    break;
+
+  case 71:
+
+/* Line 1806 of yacc.c  */
+#line 337 "regex.y"
+    { (yyval.net) = fsm_quotient_right((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));                 }
+    break;
+
+  case 72:
+
+/* Line 1806 of yacc.c  */
+#line 338 "regex.y"
+    { (yyval.net) = fsm_quotient_left((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));                  }
+    break;
+
+  case 73:
+
+/* Line 1806 of yacc.c  */
+#line 339 "regex.y"
+    { (yyval.net) = fsm_quotient_interleave((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net));            }
+    break;
+
+  case 74:
+
+/* Line 1806 of yacc.c  */
+#line 341 "regex.y"
+    { }
+    break;
+
+  case 75:
+
+/* Line 1806 of yacc.c  */
+#line 342 "regex.y"
+    { (yyval.net) = fsm_complement((yyvsp[(2) - (2)].net));       }
+    break;
+
+  case 76:
+
+/* Line 1806 of yacc.c  */
+#line 343 "regex.y"
+    { (yyval.net) = fsm_contains((yyvsp[(2) - (2)].net));         }
+    break;
+
+  case 77:
+
+/* Line 1806 of yacc.c  */
+#line 344 "regex.y"
+    { (yyval.net) = fsm_contains_one((yyvsp[(2) - (2)].net));     }
+    break;
+
+  case 78:
+
+/* Line 1806 of yacc.c  */
+#line 345 "regex.y"
+    { (yyval.net) = fsm_contains_opt_one((yyvsp[(2) - (2)].net)); }
+    break;
+
+  case 79:
+
+/* Line 1806 of yacc.c  */
+#line 347 "regex.y"
+    { }
+    break;
+
+  case 80:
+
+/* Line 1806 of yacc.c  */
+#line 349 "regex.y"
+    { }
+    break;
+
+  case 81:
+
+/* Line 1806 of yacc.c  */
+#line 350 "regex.y"
+    { (yyval.net) = fsm_kleene_star(fsm_minimize((yyvsp[(1) - (2)].net))); }
+    break;
+
+  case 82:
+
+/* Line 1806 of yacc.c  */
+#line 351 "regex.y"
+    { (yyval.net) = fsm_kleene_plus((yyvsp[(1) - (2)].net)); }
+    break;
+
+  case 83:
+
+/* Line 1806 of yacc.c  */
+#line 352 "regex.y"
+    { (yyval.net) = fsm_determinize(fsm_reverse((yyvsp[(1) - (2)].net))); }
+    break;
+
+  case 84:
+
+/* Line 1806 of yacc.c  */
+#line 353 "regex.y"
+    { (yyval.net) = fsm_invert((yyvsp[(1) - (2)].net)); }
+    break;
+
+  case 85:
+
+/* Line 1806 of yacc.c  */
+#line 354 "regex.y"
+    { (yyval.net) = fsm_upper((yyvsp[(1) - (2)].net)); }
+    break;
+
+  case 86:
+
+/* Line 1806 of yacc.c  */
+#line 355 "regex.y"
+    { (yyval.net) = fsm_lower((yyvsp[(1) - (2)].net)); }
+    break;
+
+  case 87:
+
+/* Line 1806 of yacc.c  */
+#line 356 "regex.y"
+    { (yyval.net) = flag_eliminate((yyvsp[(1) - (2)].net), NULL); }
+    break;
+
+  case 88:
+
+/* Line 1806 of yacc.c  */
+#line 357 "regex.y"
+    { (yyval.net) = fsm_cross_product((yyvsp[(1) - (3)].net),(yyvsp[(3) - (3)].net)); }
+    break;
+
+  case 89:
+
+/* Line 1806 of yacc.c  */
+#line 359 "regex.y"
+    { (yyval.net) = fsm_concat_n((yyvsp[(1) - (2)].net),atoi((yyvsp[(2) - (2)].string))); }
+    break;
+
+  case 90:
+
+/* Line 1806 of yacc.c  */
+#line 360 "regex.y"
+    { (yyval.net) = fsm_concat(fsm_concat_n(fsm_copy((yyvsp[(1) - (2)].net)), atoi((yyvsp[(2) - (2)].string))),fsm_kleene_plus(fsm_copy((yyvsp[(1) - (2)].net)))); fsm_destroy((yyvsp[(1) - (2)].net)); }
+    break;
+
+  case 91:
+
+/* Line 1806 of yacc.c  */
+#line 361 "regex.y"
+    { (yyval.net) = fsm_concat_m_n((yyvsp[(1) - (2)].net),0,atoi((yyvsp[(2) - (2)].string))-1); }
+    break;
+
+  case 92:
+
+/* Line 1806 of yacc.c  */
+#line 362 "regex.y"
+    { (yyval.net) = fsm_concat_m_n((yyvsp[(1) - (2)].net),atoi((yyvsp[(2) - (2)].string)),atoi(strstr((yyvsp[(2) - (2)].string),",")+1)); }
+    break;
+
+  case 93:
+
+/* Line 1806 of yacc.c  */
+#line 364 "regex.y"
+    { }
+    break;
+
+  case 94:
+
+/* Line 1806 of yacc.c  */
+#line 365 "regex.y"
+    { (yyval.net) = fsm_term_negation((yyvsp[(2) - (2)].net)); }
+    break;
+
+  case 95:
+
+/* Line 1806 of yacc.c  */
+#line 367 "regex.y"
+    { (yyval.net) = (yyvsp[(1) - (1)].net);}
+    break;
+
+  case 96:
+
+/* Line 1806 of yacc.c  */
+#line 368 "regex.y"
+    { (yyval.net) = (yyvsp[(1) - (1)].net); }
+    break;
+
+  case 97:
+
+/* Line 1806 of yacc.c  */
+#line 369 "regex.y"
+    { (yyval.net) = fsm_complement(fsm_substitute_symbol(fsm_intersect(fsm_quantifier((yyvsp[(1) - (4)].string)),fsm_complement((yyvsp[(3) - (4)].net))),(yyvsp[(1) - (4)].string),"@_EPSILON_SYMBOL_@")); purge_quantifier((yyvsp[(1) - (4)].string)); }
+    break;
+
+  case 98:
+
+/* Line 1806 of yacc.c  */
+#line 370 "regex.y"
+    {  (yyval.net) = fsm_substitute_symbol(fsm_intersect(fsm_quantifier((yyvsp[(1) - (2)].string)),(yyvsp[(2) - (2)].net)),(yyvsp[(1) - (2)].string),"@_EPSILON_SYMBOL_@"); purge_quantifier((yyvsp[(1) - (2)].string)); }
+    break;
+
+  case 99:
+
+/* Line 1806 of yacc.c  */
+#line 371 "regex.y"
+    { if (count_quantifiers()) (yyval.net) = (yyvsp[(2) - (3)].net); else {(yyval.net) = fsm_optionality((yyvsp[(2) - (3)].net));} }
+    break;
+
+  case 100:
+
+/* Line 1806 of yacc.c  */
+#line 372 "regex.y"
+    { (yyval.net) = (yyvsp[(2) - (3)].net); }
+    break;
+
+  case 101:
+
+/* Line 1806 of yacc.c  */
+#line 373 "regex.y"
+    {(yyval.net) = fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(2) - (5)].string)),fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(2) - (5)].string)),fsm_concat(union_quantifiers(),fsm_concat(fsm_symbol((yyvsp[(4) - (5)].string)),fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(4) - (5)].string)),fsm_universal())))))))); }
+    break;
+
+  case 102:
+
+/* Line 1806 of yacc.c  */
+#line 374 "regex.y"
+    {(yyval.net) = fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(2) - (5)].string)),fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(2) - (5)].string)),fsm_concat(fsm_ignore((yyvsp[(4) - (5)].net),union_quantifiers(),OP_IGNORE_ALL),fsm_universal()))))); }
+    break;
+
+  case 103:
+
+/* Line 1806 of yacc.c  */
+#line 375 "regex.y"
+    {(yyval.net) = fsm_concat(fsm_universal(),fsm_concat(fsm_ignore((yyvsp[(2) - (5)].net),union_quantifiers(),OP_IGNORE_ALL),fsm_concat(fsm_symbol((yyvsp[(4) - (5)].string)),fsm_concat(fsm_universal(),fsm_concat(fsm_symbol((yyvsp[(4) - (5)].string)),fsm_universal()))))); }
+    break;
+
+  case 104:
+
+/* Line 1806 of yacc.c  */
+#line 376 "regex.y"
+    {(yyval.net) = fsm_substitute_symbol((yyvsp[(1) - (2)].net),subval1,subval2); substituting = 0; xxfree(subval1); xxfree(subval2); subval1 = subval2 = NULL;}
+    break;
+
+  case 105:
+
+/* Line 1806 of yacc.c  */
+#line 378 "regex.y"
+    { (yyval.net) = (yyvsp[(3) - (4)].net); substituting = 1;                      }
+    break;
+
+  case 106:
+
+/* Line 1806 of yacc.c  */
+#line 379 "regex.y"
+    { subval1 = (yyvsp[(2) - (4)].string); subval2 = (yyvsp[(4) - (4)].string); }
+    break;
+
+  case 107:
+
+/* Line 1806 of yacc.c  */
+#line 381 "regex.y"
+    { (yyval.net) = (yyvsp[(1) - (1)].net); }
+    break;
+
+  case 108:
+
+/* Line 1806 of yacc.c  */
+#line 382 "regex.y"
+    { (yyval.net) = fsm_boolean(fsm_isidentity((yyvsp[(2) - (3)].net)));   }
+    break;
+
+  case 109:
+
+/* Line 1806 of yacc.c  */
+#line 383 "regex.y"
+    { (yyval.net) = fsm_boolean(fsm_isfunctional((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 110:
+
+/* Line 1806 of yacc.c  */
+#line 384 "regex.y"
+    { (yyval.net) = fsm_boolean(fsm_isunambiguous((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 111:
+
+/* Line 1806 of yacc.c  */
+#line 385 "regex.y"
+    { (yyval.net) = fsm_extract_nonidentity(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 112:
+
+/* Line 1806 of yacc.c  */
+#line 386 "regex.y"
+    { (yyval.net) = fsm_lowerdet(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 113:
+
+/* Line 1806 of yacc.c  */
+#line 387 "regex.y"
+    { (yyval.net) = fsm_lowerdeteps(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 114:
+
+/* Line 1806 of yacc.c  */
+#line 388 "regex.y"
+    { (yyval.net) = fsm_markallfinal(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 115:
+
+/* Line 1806 of yacc.c  */
+#line 389 "regex.y"
+    { (yyval.net) = fsm_extract_unambiguous(fsm_copy((yyvsp[(2) - (3)].net)));      }
+    break;
+
+  case 116:
+
+/* Line 1806 of yacc.c  */
+#line 390 "regex.y"
+    { (yyval.net) = fsm_extract_ambiguous(fsm_copy((yyvsp[(2) - (3)].net)));        }
+    break;
+
+  case 117:
+
+/* Line 1806 of yacc.c  */
+#line 391 "regex.y"
+    { (yyval.net) = fsm_extract_ambiguous_domain(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 118:
+
+/* Line 1806 of yacc.c  */
+#line 392 "regex.y"
+    { (yyval.net) = fsm_letter_machine(fsm_copy((yyvsp[(2) - (3)].net))); }
+    break;
+
+  case 119:
+
+/* Line 1806 of yacc.c  */
+#line 393 "regex.y"
+    { (yyval.net) = fsm_mark_fsm_tail((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net)); }
+    break;
+
+  case 120:
+
+/* Line 1806 of yacc.c  */
+#line 394 "regex.y"
+    { (yyval.net) = fsm_add_loop((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net),1); }
+    break;
+
+  case 121:
+
+/* Line 1806 of yacc.c  */
+#line 395 "regex.y"
+    { (yyval.net) = fsm_add_loop((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net),0); }
+    break;
+
+  case 122:
+
+/* Line 1806 of yacc.c  */
+#line 396 "regex.y"
+    { (yyval.net) = fsm_add_loop((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net),2); }
+    break;
+
+  case 123:
+
+/* Line 1806 of yacc.c  */
+#line 397 "regex.y"
+    { (yyval.net) = fsm_add_sink((yyvsp[(2) - (3)].net),1); }
+    break;
+
+  case 124:
+
+/* Line 1806 of yacc.c  */
+#line 398 "regex.y"
+    { (yyval.net) = fsm_left_rewr((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net)); }
+    break;
+
+  case 125:
+
+/* Line 1806 of yacc.c  */
+#line 399 "regex.y"
+    { (yyval.net) = fsm_flatten((yyvsp[(2) - (5)].net),(yyvsp[(4) - (5)].net)); }
+    break;
+
+  case 126:
+
+/* Line 1806 of yacc.c  */
+#line 400 "regex.y"
+    { (yyval.net) = fsm_substitute_label((yyvsp[(2) - (7)].net), fsm_network_to_char((yyvsp[(4) - (7)].net)), (yyvsp[(6) - (7)].net)); }
+    break;
+
+  case 127:
+
+/* Line 1806 of yacc.c  */
+#line 401 "regex.y"
+    { (yyval.net) = fsm_close_sigma(fsm_copy((yyvsp[(2) - (3)].net)), 0); }
+    break;
+
+  case 128:
+
+/* Line 1806 of yacc.c  */
+#line 402 "regex.y"
+    { (yyval.net) = fsm_close_sigma(fsm_copy((yyvsp[(2) - (3)].net)), 1); }
+    break;
+
+  case 129:
+
+/* Line 1806 of yacc.c  */
+#line 403 "regex.y"
+    { (yyval.net) = fsm_equal_substrings((yyvsp[(2) - (7)].net),(yyvsp[(4) - (7)].net),(yyvsp[(6) - (7)].net)); }
+    break;
+
+  case 130:
+
+/* Line 1806 of yacc.c  */
+#line 406 "regex.y"
+    { frec++; fargptr[frec] = 0 ;declare_function_name((yyvsp[(1) - (3)].string)) ; add_function_argument((yyvsp[(2) - (3)].net)); }
+    break;
+
+  case 131:
+
+/* Line 1806 of yacc.c  */
+#line 408 "regex.y"
+    { frec++; fargptr[frec] = 0 ;declare_function_name((yyvsp[(1) - (2)].string)) ; add_function_argument((yyvsp[(2) - (2)].net)); }
+    break;
+
+  case 132:
+
+/* Line 1806 of yacc.c  */
+#line 410 "regex.y"
+    { add_function_argument((yyvsp[(2) - (3)].net)); }
+    break;
+
+  case 133:
+
+/* Line 1806 of yacc.c  */
+#line 411 "regex.y"
+    { add_function_argument((yyvsp[(2) - (3)].net)); }
+    break;
+
+  case 134:
+
+/* Line 1806 of yacc.c  */
+#line 414 "regex.y"
+    { add_function_argument((yyvsp[(2) - (3)].net)); if (((yyval.net) = function_apply(defined_nets, defined_funcs)) == NULL) YYERROR; }
+    break;
+
+  case 135:
+
+/* Line 1806 of yacc.c  */
+#line 416 "regex.y"
+    { add_function_argument((yyvsp[(2) - (3)].net)); if (((yyval.net) = function_apply(defined_nets, defined_funcs)) == NULL) YYERROR; }
+    break;
+
+  case 136:
+
+/* Line 1806 of yacc.c  */
+#line 418 "regex.y"
+    { if (((yyval.net) = function_apply(defined_nets, defined_funcs)) == NULL) YYERROR;}
+    break;
+
+
+
+/* Line 1806 of yacc.c  */
+#line 3104 "regex.c"
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+  *++yylsp = yyloc;
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      //yyerror (&yylloc, scanner, defined_nets, defined_funcs, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
+      {
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        //yyerror (&yylloc, scanner, defined_nets, defined_funcs, yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+  yyerror_range[1] = yylloc;
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval, &yylloc, scanner, defined_nets, defined_funcs);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  yyerror_range[1] = yylsp[1-yylen];
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      yyerror_range[1] = *yylsp;
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp, yylsp, scanner, defined_nets, defined_funcs);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  *++yyvsp = yylval;
+
+  yyerror_range[2] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the lookahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+  *++yylsp = yyloc;
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  //yyerror (&yylloc, scanner, defined_nets, defined_funcs, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval, &yylloc, scanner, defined_nets, defined_funcs);
+    }
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp, yylsp, scanner, defined_nets, defined_funcs);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
+/* Line 2067 of yacc.c  */
+#line 420 "regex.y"
+
+
diff --git a/back-ends/foma/cpp-version/reverse.cc b/back-ends/foma/cpp-version/reverse.cc
new file mode 100644
index 0000000..eb9f1c3
--- /dev/null
+++ b/back-ends/foma/cpp-version/reverse.cc
@@ -0,0 +1,48 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdlib.h>
+#include "foma.h"
+
+struct fsm *fsm_reverse(struct fsm *net) {
+    struct fsm *revnet;
+    struct fsm_construct_handle *revh;
+    struct fsm_read_handle *inh;
+    int i;
+
+    inh = fsm_read_init(net);
+    revh = fsm_construct_init(net->name);
+    fsm_construct_copy_sigma(revh, net->sigma);
+
+    while (fsm_get_next_arc(inh)) {
+	fsm_construct_add_arc_nums(revh, fsm_get_arc_target(inh)+1, fsm_get_arc_source(inh)+1, fsm_get_arc_num_in(inh), fsm_get_arc_num_out(inh));
+    }
+
+    while ((i = fsm_get_next_final(inh)) != -1) {
+	fsm_construct_add_arc_nums(revh, 0, i+1, EPSILON, EPSILON);
+    }
+    while ((i = fsm_get_next_initial(inh)) != -1) {
+	fsm_construct_set_final(revh, i+1);
+    }
+    fsm_construct_set_initial(revh, 0);
+    fsm_read_done(inh);
+    revnet = fsm_construct_done(revh);
+    revnet->is_deterministic = 0;
+    revnet->is_epsilon_free = 0;
+    fsm_destroy(net);
+    return(revnet);
+}
diff --git a/back-ends/foma/cpp-version/rewrite.cc b/back-ends/foma/cpp-version/rewrite.cc
new file mode 100644
index 0000000..5a95879
--- /dev/null
+++ b/back-ends/foma/cpp-version/rewrite.cc
@@ -0,0 +1,610 @@
+/*   Foma: a finite-state toolkit and library.                                 */
+/*   Copyright © 2008-2015 Mans Hulden                                         */
+
+/*   This file is part of foma.                                                */
+
+/*   Licensed under the Apache License, Version 2.0 (the "License");           */
+/*   you may not use this file except in compliance with the License.          */
+/*   You may obtain a copy of the License at                                   */
+
+/*      http://www.apache.org/licenses/LICENSE-2.0                             */
+
+/*   Unless required by applicable law or agreed to in writing, software       */
+/*   distributed under the License is distributed on an "AS IS" BASIS,         */
+/*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
+/*   See the License for the specific language governing permissions and       */
+/*   limitations under the License.                                            */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "foma.h"
+
+// Lower(X) puts X on output tape (may also be represented by @ID@ on input tape)
+// Upper(X) puts X on input tape
+// Unrewritten(X) X on input tape, not rewritten (aligned with @O@ symbols)
+// NotContain(X) MT does not contain MT configuration X
+
+// Boundary: every MT word begins and ends with boundary, i.e. the @#@ symbol on the input tape, output tape, and relevant semantic symbols
+
+/*
+
+       [ @O@  ]  [ @I[@        ] [ @I@         ] [ @I]@        ] [ @I[]@       ]
+       [ @0@  ]  [ @#0001@     ] [ @#0001@     ] [ @#0001@     ] [ @#0001@     ]
+       [ @#@  ]  [ ANY|@0@     ] [ ANY|@0@     ] [ ANY|@0@     ] [ ANY|@0@     ]
+       [ @ID@ ]  [ ANY|@ID|@0@ ] [ ANY|@ID|@0@ ] [ ANY|@ID|@0@ ] [ ANY|@ID|@0@ ]
+
+
+*/
+/* Special symbols used:
+   @0@    Epsilon
+   @O@    Outside rewrite
+   @I@    Inside rewrite
+   @I[@   Beginning of rewrite
+   @I[]@  Beginning and end of rewrite
+   @I]@   End of rewrite
+   @ID@   Identity symbol (= repeat symbol on previous tape at this position)
+   @#@    Boundary (the symbol .#. is mapped to this in contexts before the compilation procedure)
+   @#X@   X = rule number (one for each rule, starting with @#0001@)
+*/
+
+struct rewrite_batch {
+
+    struct rewrite_set *rewrite_set;
+    struct fsm *Rulenames;
+    struct fsm *ISyms;
+    struct fsm *ANY;
+    struct fsm *IOpen;
+    struct fsm *IClose;
+    struct fsm *ITape;
+    struct fsm *Any4Tape;
+    struct fsm *Epextend;
+    int num_rules;
+    char (*namestrings)[8];
+
+};
+
+char *specialsymbols[] = {"@0@","@O@","@I@","@I[@","@I[]@","@I]@","@ID@","@#@", NULL};
+
+void rewrite_add_special_syms(struct rewrite_batch *rb, struct fsm *net);
+struct fsm *rewrite_upper(struct rewrite_batch *rb, struct fsm *upper);
+struct fsm *rewrite_lower(struct rewrite_batch *rb, struct fsm *lower);
+struct fsm *rewrite_two_level(struct rewrite_batch *rb, struct fsm *lang, int rightside);
+struct fsm *rewr_context_restrict(struct rewrite_batch *rb, struct fsm *X, struct fsmcontexts *LR);
+struct fsm *rewr_contains(struct rewrite_batch *rb, struct fsm *lang);
+struct fsm *rewr_unrewritten(struct rewrite_batch *rb, struct fsm *lang);
+struct fsm *rewr_notleftmost(struct rewrite_batch *rb, struct fsm *lang, int rule_number, int arrow_type);
+struct fsm *rewr_notshortest(struct rewrite_batch *rb, struct fsm *lang, int rule_number);
+struct fsm *rewr_notlongest(struct rewrite_batch *rb, struct fsm *lang, int rule_number, int arrow_type);
+struct fsm *rewrite_tape_m_to_n_of_k(struct fsm *lang, int m, int n, int k);
+struct fsm *rewrite_cp(struct rewrite_batch *rb, struct fsm *upper, struct fsm *lower, int rule_number);
+struct fsm *rewrite_cp_transducer(struct rewrite_batch *rb, struct fsm *t, int rule_number);
+struct fsm *rewrite_cp_markup(struct rewrite_batch *rb, struct fsm *upper, struct fsm *lower1, struct fsm *lower2, int rule_number);
+struct fsm *rewrite_epextend(struct rewrite_batch *rb);
+struct fsm *rewrite_any_4tape(struct rewrite_batch *rb);
+struct fsm *rewrite_itape(struct rewrite_batch *rb);
+void rewrite_cleanup(struct rewrite_batch *rb);
+
+
+struct fsm *fsm_rewrite(struct rewrite_set *all_rules) {
+    struct rewrite_batch *rb;
+    struct rewrite_set *ruleset;
+    struct fsmrules *rules;
+    struct fsmcontexts *contexts;
+    struct fsm *RuleCP, *Base, *Boundary, *Outside, *CP, *C, *LeftExtend, *RightExtend, *Center;
+    int i, num_rules, rule_number, dir;
+    /* Count parallel rules */
+    for (ruleset = all_rules, num_rules = 0; ruleset != NULL; ruleset = ruleset->next) {
+	for (rules = ruleset->rewrite_rules; rules != NULL; rules = rules->next) {
+	     num_rules++;
+	 }
+    }
+
+    rb = (struct rewrite_batch*)xxcalloc(1, sizeof(struct rewrite_batch));
+    rb->rewrite_set = all_rules;
+    rb->num_rules = num_rules;
+    rb->namestrings = (char (*)[8])xxmalloc(sizeof rb->namestrings * num_rules);
+    for (i = 0; i < rb->num_rules; i++) {
+	sprintf(rb->namestrings[i], "@#%04i@", i+1);
+    }
+
+    rb->ISyms = fsm_minimize(fsm_union(fsm_symbol("@I@"), fsm_union(fsm_symbol("@I[]@"), fsm_union(fsm_symbol("@I[@"), fsm_symbol("@I]@")))));
+    rb->Rulenames = fsm_empty_set();
+    for (i = 1; i <= num_rules; i++) {
+	rb->Rulenames = fsm_minimize(fsm_union(rb->Rulenames, fsm_symbol(rb->namestrings[i-1])));
+    }
+    rb->ANY = fsm_identity();
+    rewrite_add_special_syms(rb, rb->ANY);
+
+    /* Add auxiliary symbols to all alphabets */
+    for (ruleset = all_rules; ruleset != NULL; ruleset = ruleset->next) {
+        for (rules = ruleset->rewrite_rules; rules != NULL; rules = rules->next) {
+            rewrite_add_special_syms(rb, rules->left);
+	    rewrite_add_special_syms(rb, rules->right);
+            rewrite_add_special_syms(rb, rules->right2);
+        }
+        for (contexts = ruleset->rewrite_contexts; contexts != NULL; contexts = contexts->next) {
+            rewrite_add_special_syms(rb, contexts->left);
+            rewrite_add_special_syms(rb, contexts->right);
+        }
+    }
+    /* Get cross-product of every rule, according to its type */
+    RuleCP = fsm_empty_set();
+    for (ruleset = all_rules, rule_number = 1; ruleset != NULL; ruleset = ruleset->next) {
+	dir = ruleset->rule_direction;
+        for (rules = ruleset->rewrite_rules; rules != NULL; rules = rules->next) {
+	    if (rules->right == NULL) {
+		/* T(x)-type rule */
+		CP = rewrite_cp_transducer(rb, fsm_copy(rules->left), rule_number);
+		rules->cross_product = fsm_copy(CP);
+		rules->right = fsm_minimize(fsm_lower(fsm_copy(rules->left)));
+		rules->left = fsm_minimize(fsm_upper(fsm_copy(rules->left)));
+		rewrite_add_special_syms(rb, rules->right);
+		rewrite_add_special_syms(rb, rules->left);
+	    } else if (rules->right2 == NULL) {
+		/* Regular rewrite rule */
+		CP = rewrite_cp(rb, fsm_copy(rules->left), fsm_copy(rules->right), rule_number);
+		rules->cross_product = fsm_copy(CP);
+	    } else {
+		/* A -> B ... C -type rule */
+		CP = rewrite_cp_markup(rb, fsm_copy(rules->left), fsm_copy(rules->right), fsm_copy(rules->right2), rule_number);
+		rules->cross_product = fsm_copy(CP);
+	    }
+	    RuleCP = fsm_minimize(fsm_union(RuleCP, CP));
+	    rule_number++;
+	}
+    }
+
+    /* Create Base language */
+    Boundary = fsm_parse_regex("\"@O@\" \"@0@\" \"@#@\" \"@ID@\"", NULL, NULL);
+    Outside = fsm_minimize(fsm_concat(fsm_symbol("@O@"), fsm_concat(fsm_symbol("@0@"), fsm_concat(fsm_copy(rb->ANY), fsm_symbol("@ID@")))));
+    Base = fsm_minimize(fsm_concat(fsm_copy(Boundary), fsm_concat(fsm_kleene_star(fsm_union(RuleCP, Outside)), fsm_copy(Boundary))));
+    fsm_destroy(Boundary);
+    for (ruleset = all_rules, rule_number = 1; ruleset != NULL; ruleset = ruleset->next) {
+	dir = ruleset->rule_direction;
+	/* Replace all context spec with Upper/Lower, depending on rule_direction */
+	for (contexts = ruleset->rewrite_contexts; contexts != NULL; contexts = contexts->next) {
+	    switch(dir) {
+	    case OP_UPWARD_REPLACE:
+		contexts->cpleft = rewrite_upper(rb, fsm_copy(contexts->left));
+		contexts->cpright = rewrite_upper(rb, fsm_copy(contexts->right));
+		break;
+	    case OP_RIGHTWARD_REPLACE:
+		contexts->cpleft = rewrite_lower(rb, fsm_copy(contexts->left));
+		contexts->cpright = rewrite_upper(rb, fsm_copy(contexts->right));
+		break;
+	    case OP_LEFTWARD_REPLACE:
+		contexts->cpleft = rewrite_upper(rb, fsm_copy(contexts->left));
+		contexts->cpright = rewrite_lower(rb, fsm_copy(contexts->right));
+		break;
+	    case OP_DOWNWARD_REPLACE:
+		contexts->cpleft = rewrite_lower(rb, fsm_copy(contexts->left));
+		contexts->cpright = rewrite_lower(rb, fsm_copy(contexts->right));
+		break;
+	    case OP_TWO_LEVEL_REPLACE:
+		contexts->cpleft = rewrite_two_level(rb, fsm_copy(contexts->left), 0);
+		contexts->cpright = rewrite_two_level(rb, fsm_copy(contexts->right), 1);
+		break;
+	    }
+	}
+        for (rules = ruleset->rewrite_rules; rules != NULL; rules = rules->next) {
+	    /* Just the rule center w/ number without CP() contests */
+	    /* Actually, maybe better to include CP(U,L) in this, very slow with e.g. a -> a || _ b^15 */
+	    if (rules->arrow_type & ARROW_DOTTED) {
+		/* define EP Tape1of4("@O@") | [ Tape1of4("@I[@" "@I@"* "@I]@" | "@I[]@") & Tape3of4(~["@0@"*]) ] ; */
+		/* Additional constraint: 0->x is only allowed between EP _ EP */
+		/* The left and right sides can be checked separately */
+		/* ~[?* Center ~[EP ?*]] & ~[~[?* EP] Center ?*] */
+		Center = fsm_copy(rules->cross_product);
+		Base = fsm_intersect(fsm_intersect(Base, fsm_complement(fsm_concat(rewrite_any_4tape(rb), fsm_concat(fsm_copy(Center), fsm_complement(fsm_concat(rewrite_epextend(rb), rewrite_any_4tape(rb))))))), fsm_complement(fsm_concat(fsm_complement(fsm_concat(rewrite_any_4tape(rb), rewrite_epextend(rb))), fsm_concat(fsm_copy(Center), rewrite_any_4tape(rb)))));
+	    }
+	    if (ruleset->rewrite_contexts) {
+		Base = fsm_intersect(Base, rewr_context_restrict(rb, rules->cross_product, ruleset->rewrite_contexts));
+	    }
+	    /* Determine C (based on rule type) */
+	    C = fsm_empty_set();
+	    if ((rules->arrow_type & ARROW_RIGHT) && !(rules->arrow_type & ARROW_OPTIONAL)) {
+		C = fsm_union(C, rewr_unrewritten(rb, fsm_minimize(fsm_minus(fsm_copy(rules->left), fsm_empty_string()))));
+	    }
+	    if ((rules->arrow_type & ARROW_LEFT) && !(rules->arrow_type & ARROW_OPTIONAL)) {
+		C = fsm_union(C, rewr_unrewritten(rb, fsm_minimize(fsm_minus(fsm_copy(rules->right), fsm_empty_string()))));
+	    }
+	    if (rules->arrow_type & ARROW_LONGEST_MATCH) {
+		if (rules->arrow_type & ARROW_RIGHT) {
+		    C = fsm_union(C, rewr_notleftmost(rb, rewrite_upper(rb, fsm_copy(rules->left)), rule_number, rules->arrow_type));
+		    C = fsm_union(C, rewr_notlongest(rb, rewrite_upper(rb, fsm_copy(rules->left)), rule_number, rules->arrow_type));
+		}
+		if (rules->arrow_type & ARROW_LEFT) {
+		    C = fsm_union(C, rewr_notleftmost(rb, rewrite_lower(rb, fsm_copy(rules->right)), rule_number, rules->arrow_type));
+		    C = fsm_union(C, rewr_notlongest(rb, rewrite_lower(rb, fsm_copy(rules->right)), rule_number, rules->arrow_type));
+		}
+	    }
+	    if (rules->arrow_type & ARROW_SHORTEST_MATCH) {
+		if (rules->arrow_type & ARROW_RIGHT) {		
+		    C = fsm_union(C, rewr_notleftmost(rb, rewrite_upper(rb, fsm_copy(rules->left)), rule_number, rules->arrow_type));
+		    C = fsm_union(C, rewr_notshortest(rb, rewrite_upper(rb, fsm_copy(rules->left)), rule_number));
+		}
+		if (rules->arrow_type & ARROW_LEFT) {
+		    C = fsm_union(C, rewr_notleftmost(rb, rewrite_lower(rb, fsm_copy(rules->right)), rule_number, rules->arrow_type));
+		    C = fsm_union(C, rewr_notshortest(rb, rewrite_lower(rb, fsm_copy(rules->right)), rule_number));
+		}
+	    }
+	    if (!ruleset->rewrite_contexts) {
+		if (rules->arrow_type & ARROW_DOTTED && !(rules->arrow_type & ARROW_OPTIONAL)) {
+		    Base = fsm_minus(Base, rewr_contains(rb, fsm_concat(rewrite_epextend(rb), rewrite_epextend(rb))));
+		} else {
+		    Base = fsm_minus(Base, rewr_contains(rb, fsm_copy(C)));
+		}
+	    }
+	    for (contexts = ruleset->rewrite_contexts; contexts != NULL; contexts = contexts->next) {
+		/* Constraints: running intersect w/ Base */
+		/* NotContain(LC [Unrewritten|LM|...] RC) */
+		if (rules->arrow_type & ARROW_DOTTED && !(rules->arrow_type & ARROW_OPTIONAL)) {
+		    /* Extend left and right */
+		    LeftExtend = fsm_minimize(fsm_intersect(fsm_concat(rewrite_any_4tape(rb), fsm_copy(contexts->cpleft)), fsm_concat(rewrite_any_4tape(rb), rewrite_epextend(rb))));
+		    RightExtend = fsm_minimize(fsm_intersect(fsm_concat(rewrite_epextend(rb), rewrite_any_4tape(rb)), fsm_concat(fsm_copy(contexts->cpright), rewrite_any_4tape(rb))));
+		    Base = fsm_minus(Base, rewr_contains(rb, fsm_minimize(fsm_concat(LeftExtend, RightExtend))));
+		} else {
+		    Base = fsm_minus(Base, rewr_contains(rb, fsm_concat(fsm_copy(contexts->cpleft), fsm_concat(fsm_copy(C), fsm_copy(contexts->cpright)))));
+		}
+	    }
+	    rule_number++;
+	    fsm_destroy(C);
+	}
+    }
+    Base = fsm_minimize(fsm_lower(fsm_compose(Base, fsm_parse_regex("[?:0]^4 [?:0 ?:0 ? ?]* [?:0]^4", NULL, NULL))));
+    Base = fsm_unflatten(Base, "@0@", "@ID@");
+
+    for (i = 0; specialsymbols[i] != NULL; i++) {
+	Base->sigma = sigma_remove(specialsymbols[i], Base->sigma);
+    }
+    for (rule_number = 1; rule_number <= num_rules; rule_number++)
+	Base->sigma = sigma_remove(rb->namestrings[rule_number-1], Base->sigma);
+
+    fsm_compact(Base);
+    sigma_sort(Base);
+    rewrite_cleanup(rb);
+    return Base;
+}
+
+void rewrite_cleanup(struct rewrite_batch *rb) {
+
+    if (rb->Rulenames != NULL)
+	fsm_destroy(rb->Rulenames);
+    if (rb->ISyms != NULL)
+	fsm_destroy(rb->ISyms);
+    if (rb->ANY != NULL)
+	fsm_destroy(rb->ANY);
+    if (rb->IOpen != NULL)
+	fsm_destroy(rb->IOpen);
+    if (rb->IClose != NULL)
+	fsm_destroy(rb->IClose);
+    if (rb->ITape != NULL)
+	fsm_destroy(rb->ITape);
+    if (rb->Any4Tape != NULL)
+	fsm_destroy(rb->Any4Tape);
+    if (rb->Epextend != NULL)
+	fsm_destroy(rb->Epextend);
+    if (rb->namestrings != NULL)
+	xxfree(rb->namestrings);
+    xxfree(rb);
+    return;
+}
+
+
+struct fsm *rewr_notlongest(struct rewrite_batch *rb, struct fsm *lang, int rule_number, int arrow_type) {
+    /* define NotLongest(X)  [Upper(X)/Lower(X) & Tape1of4(IOpen Tape1Sig* ["@O@" | IOpen] Tape1Sig*)] */
+    struct fsm *nl, *flt, *rulenum;
+    nl = fsm_parse_regex("[\"@I[@\"|\"@I[]@\"] [\"@I[@\"|\"@I[]@\"|\"@I]@\"|\"@I@\"|\"@O@\"]* [\"@O@\"|\"@I[@\"|\"@I[]@\"] [\"@I[@\"|\"@I[]@\"|\"@I]@\"|\"@I@\"|\"@O@\"]*", NULL, NULL);
+    nl = rewrite_tape_m_to_n_of_k(nl, 1, 1, 4);
+    rulenum = fsm_minimize(fsm_concat(fsm_identity(), fsm_concat(fsm_symbol(rb->namestrings[rule_number-1]), fsm_concat(fsm_identity(), fsm_concat(fsm_identity(), fsm_universal())))));
+    nl = fsm_intersect(nl, rulenum);
+    /* lang can't end in @0@ */
+    if (arrow_type & ARROW_RIGHT) {
+	flt = fsm_parse_regex("[? ? ? ?]* [? ? [?-\"@0@\"] ?]", NULL, NULL);
+    } else {
+	flt = fsm_parse_regex("[? ? ? ?]* [? ? ? [?-\"@0@\"]]", NULL, NULL);
+    }
+    return fsm_minimize(fsm_intersect(fsm_intersect(nl, fsm_copy(lang)), flt));
+}
+
+struct fsm *rewr_notshortest(struct rewrite_batch *rb, struct fsm *lang, int rule_number) {
+    /* define NotShortest(X)   [Upper/Lower(X) & Tape1of4("@I[@" \IClose*)] */
+    struct fsm *ns, *rulenum;
+    ns = fsm_parse_regex("[\"@I[@\"] \\[\"@I]@\"]*", NULL, NULL);
+    rulenum = fsm_minimize(fsm_concat(fsm_identity(), fsm_concat(fsm_symbol(rb->namestrings[rule_number-1]), fsm_concat(fsm_identity(), fsm_concat(fsm_identity(), fsm_universal())))));
+    ns = rewrite_tape_m_to_n_of_k(ns, 1, 1, 4);
+    ns = fsm_intersect(ns, rulenum);
+    return fsm_minimize(fsm_intersect(ns, fsm_copy(lang)));
+}
+
+struct fsm *rewr_notleftmost(struct rewrite_batch *rb, struct fsm *lang, int rule_number, int arrow_type) {
+    struct fsm *nl, *flt, *rulenum;
+    /* define Leftmost(X)   [Upper/Lower(X) & Tape1of4("@O@" Tape1Sig* IOpen Tape1Sig*) ] */
+    nl = fsm_parse_regex("\"@O@\" [\"@O@\"]* [\"@I[@\"|\"@I[]@\"] [\"@I[@\"|\"@I[]@\"|\"@I]@\"|\"@I@\"|\"@O@\"]*", NULL, NULL);
+    nl = rewrite_tape_m_to_n_of_k(nl, 1, 1, 4);
+    rulenum = fsm_minimize(fsm_concat(fsm_concat(fsm_symbol("@O@"), fsm_concat(fsm_identity(), fsm_concat(fsm_identity(), fsm_identity()))), fsm_concat(fsm_kleene_star(fsm_concat(fsm_symbol("@O@"), fsm_concat(fsm_identity(), fsm_concat(fsm_identity(), fsm_identity())))), fsm_concat(fsm_union(fsm_symbol("@I[@"), fsm_symbol("@I[]@")), fsm_concat(fsm_symbol(rb->namestrings[rule_number-1]), fsm_universal())))));
+    nl = fsm_intersect(nl, rulenum);
+    if (arrow_type & ARROW_RIGHT) {
+	flt = fsm_parse_regex("[? ? ? ?]* [? ? [?-\"@0@\"] ?]", NULL, NULL); 
+    } else {
+	flt = fsm_parse_regex("[? ? ? ?]* [? ? ? [?-\"@0@\"]]", NULL, NULL);
+    }
+    return fsm_minimize(fsm_intersect(fsm_intersect(nl, fsm_copy(lang)), flt));
+}
+
+struct fsm *rewr_unrewritten(struct rewrite_batch *rb, struct fsm *lang) {
+    /* define Unrewritten(X) [X .o. [0:"@O@" 0:"@0@" ? 0:"@ID@"]*].l; */
+    struct fsm *C;
+    C = fsm_minimize(fsm_kleene_star(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@O@")), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@0@")), fsm_concat(fsm_copy(rb->ANY), fsm_cross_product(fsm_empty_string(), fsm_symbol("@ID@")))))));
+    return fsm_minimize(fsm_lower(fsm_compose(lang, C)));
+}
+
+struct fsm *rewr_contains(struct rewrite_batch *rb, struct fsm *lang) {
+    /* define NotContain(X) ~[[Tape1Sig Tape2Sig Tape3Sig Tape4Sig]* X ?*]; */
+    return fsm_minimize(fsm_concat(rewrite_any_4tape(rb), fsm_concat(lang, rewrite_any_4tape(rb))));
+}
+
+struct fsm *rewrite_tape_m_to_n_of_k(struct fsm *lang, int m, int n, int k) {
+    /* [X .o. [0:?^(m-1) ?^(n-m+1) 0:?^(k-n)]*].l */
+    return fsm_minimize(fsm_lower(fsm_compose(lang, fsm_kleene_star(fsm_concat(fsm_concat_n(fsm_cross_product(fsm_empty_string(), fsm_identity()), m-1), fsm_concat(fsm_concat_n(fsm_identity(), n-m+1), fsm_concat_n(fsm_cross_product(fsm_empty_string(), fsm_identity()), k-n)))))));
+}
+
+struct fsm *rewrite_two_level(struct rewrite_batch *rb, struct fsm *lang, int rightside) {
+    struct fsm *Lower, *Upper, *Result;
+    Lower = rewrite_lower(rb, fsm_minimize(fsm_lower(fsm_copy(lang))));
+    Upper = rewrite_upper(rb, fsm_minimize(fsm_upper(lang)));
+    if (rightside == 1) {
+	Result = fsm_minimize(fsm_intersect(fsm_concat(Lower, rewrite_any_4tape(rb)), fsm_concat(Upper, rewrite_any_4tape(rb))));
+    } else {
+	Result = fsm_minimize(fsm_intersect(fsm_concat(rewrite_any_4tape(rb), Lower), fsm_concat(rewrite_any_4tape(rb), Upper)));
+    }
+    return Result;
+}
+
+struct fsm *rewrite_lower(struct rewrite_batch *rb, struct fsm *lower) {
+
+    /*
+       Lower:
+
+       [ @O@      | ISyms    | ISyms    ]*
+       [ @0@      | Rulenums | Rulenums ]
+       [ <R>,@#@  | @0@,R    |  R       ]
+       [ @ID@     | <R>      | @0@      ]
+
+       R = any real symbol
+       <R> = any real symbol, not inserted
+
+    */
+
+    struct fsm *One, *Two, *Three, *Filter;
+
+    One = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@O@")), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@0@")), fsm_concat(fsm_union(fsm_symbol("@#@"), fsm_copy(rb->ANY)), fsm_cross_product(fsm_empty_string(),fsm_symbol("@ID@"))))));
+
+    Two = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ISyms)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->Rulenames)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_union(fsm_copy(rb->ANY), fsm_symbol("@0@"))), fsm_copy(rb->ANY)))));
+
+    Three = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ISyms)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->Rulenames)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ANY)), fsm_cross_product(fsm_empty_string(), fsm_symbol("@0@"))))));
+
+    Filter = fsm_minimize(fsm_kleene_star(fsm_union(One, fsm_union(Two, Three))));
+    return fsm_minimize(fsm_lower(fsm_compose(lower, Filter)));
+}
+
+struct fsm *rewrite_any_4tape(struct rewrite_batch *rb) {
+
+    /*
+      Upper:
+
+      [ @O@      | ISyms      ]*
+      [ @0@      | Rulenums   ]
+      [ <R>,@#@  | @0@,R      ]
+      [ @ID@     | R, at ID@, at 0@ ]
+
+      R = any real symbol
+      <R> = any real symbol, not inserted
+    */
+    if (rb->Any4Tape == NULL) {
+	rb->Any4Tape = fsm_minimize(fsm_kleene_star(fsm_union(fsm_concat(fsm_symbol("@O@"), fsm_concat(fsm_symbol("@0@"), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@#@")), fsm_symbol("@ID@")))), fsm_concat(fsm_copy(rb->ISyms), fsm_concat(fsm_copy(rb->Rulenames), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@0@")), fsm_union(fsm_copy(rb->ANY), fsm_union(fsm_symbol("@ID@"), fsm_symbol("@0@")))))))));
+    }
+    return fsm_copy(rb->Any4Tape);
+}
+
+struct fsm *rewrite_upper(struct rewrite_batch *rb, struct fsm *upper) {
+    /*
+      Upper:
+
+      [ @O@      | ISyms    | ISyms      ]*
+      [ @0@      | Rulenums | Rulenums   ]
+      [ <R>,@#@  | @0@      | <R>        ]
+      [ @ID@     |  R       | R, at ID@, at 0@ ]
+
+      R = any real symbol
+      <R> = any real symbol, not inserted
+    */
+
+    struct fsm *One, *Two, *Three, *Filter;
+
+    One = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@O@")), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@0@")), fsm_concat(fsm_union(fsm_symbol("@#@"), fsm_copy(rb->ANY)), fsm_cross_product(fsm_empty_string(),fsm_symbol("@ID@"))))));
+
+    Two = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ISyms)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->Rulenames)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_symbol("@0@")), fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ANY))))));
+
+    Three = fsm_minimize(fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->ISyms)), fsm_concat(fsm_cross_product(fsm_empty_string(), fsm_copy(rb->Rulenames)), fsm_concat(fsm_copy(rb->ANY), fsm_cross_product(fsm_empty_string(), fsm_union(fsm_union(fsm_symbol("@0@"), fsm_copy(rb->ANY)), fsm_symbol("@ID@")))))));
+
+    Filter = fsm_minimize(fsm_kleene_star(fsm_union(One, fsm_union(Two, Three))));
+    return fsm_minimize(fsm_lower(fsm_compose(upper, Filter)));
+}
+
+struct fsm *rewrite_align(struct fsm *upper, struct fsm *lower) {
+    struct fsm *first, *second, *third, *align, *align2;
+    /* `[[`[[Tape1of2(upper "@0@"*) & Tape2of2(lower "@0@"*) & ~[[? ?]* "@0@" "@0@" [? ?]*]], %@%_IDENTITY%_SYMBOL%_%@,%@UNK%@] .o. [? ?|"@UNK@" "@UNK@":"@ID@"]*].l, %@UNK%@,%@%_IDENTITY%_SYMBOL%_%@] */
+    first = fsm_minimize(rewrite_tape_m_to_n_of_k(fsm_concat(upper, fsm_kleene_star(fsm_symbol("@0@"))), 1, 1, 2));
+    second = fsm_minimize(rewrite_tape_m_to_n_of_k(fsm_concat(lower, fsm_kleene_star(fsm_symbol("@0@"))), 2, 2, 2));
+    third = fsm_minimize(fsm_parse_regex("~[[? ?]* \"@0@\" \"@0@\" [? ?]*]", NULL, NULL));
+
+    align = fsm_minimize(fsm_intersect(third, fsm_intersect(first, second)));
+    align = fsm_minimize(fsm_substitute_symbol(align, "@_IDENTITY_SYMBOL_@", "@UNK@"));
+    align2 = fsm_minimize(fsm_lower(fsm_compose(align, fsm_parse_regex("[? ? | \"@UNK@\" \"@UNK@\":\"@ID@\" ]*", NULL, NULL))));
+    align2 = fsm_minimize(fsm_substitute_symbol(align2, "@UNK@", "@_IDENTITY_SYMBOL_@"));
+    return align2;
+}
+
+struct fsm *rewrite_align_markup(struct fsm *upper, struct fsm *lower1, struct fsm *lower2) {
+    struct fsm *first, *second, *third, *fourth, *fifth, *sixth, *align, *align2;
+    /* [Tape1of2("@0@"*) & Tape2of2(lower1)] [Tape1of2(upper) & Tape2of2("@ID@"*)] [ Tape1of2(lower1) & Tape2of2("@0@"*)] */
+    /* + make sure IDENTITY and UNKNOWN are taken care of */
+    first = fsm_minimize(rewrite_tape_m_to_n_of_k(fsm_kleene_star(fsm_symbol("@0@")), 1, 1, 2));
+    second = fsm_minimize(rewrite_tape_m_to_n_of_k(lower1, 2, 2, 2));
+    third = fsm_minimize(rewrite_tape_m_to_n_of_k(upper, 1, 1, 2));
+    fourth = fsm_minimize(rewrite_tape_m_to_n_of_k(fsm_kleene_star(fsm_symbol("@ID@")), 2, 2, 2));
+    fifth = fsm_minimize(rewrite_tape_m_to_n_of_k(fsm_kleene_star(fsm_symbol("@0@")), 1, 1, 2));
+    sixth = fsm_minimize(rewrite_tape_m_to_n_of_k(lower2, 2, 2, 2));
+    align = fsm_minimize(fsm_concat(fsm_intersect(first, second), fsm_concat(fsm_intersect(third, fourth), fsm_intersect(fifth, sixth))));
+    align = fsm_minimize(fsm_substitute_symbol(align, "@_IDENTITY_SYMBOL_@", "@UNK@"));
+    align2 = fsm_minimize(fsm_lower(fsm_compose(align, fsm_parse_regex("[? ? | \"@UNK@\" \"@UNK@\":\"@ID@\" ]*", NULL, NULL))));
+    align2 = fsm_minimize(fsm_substitute_symbol(align2, "@UNK@", "@_IDENTITY_SYMBOL_@"));
+    return align2;
+}
+
+struct fsm *rewrite_itape(struct rewrite_batch *rb) {
+    if (rb->ITape == NULL) {
+	rb->ITape = fsm_parse_regex("[\"@I[]@\" ? ? ? | \"@I[@\" ? ? ? [\"@I@\" ? ? ?]* \"@I]@\" ? [?-\"@0@\"] ? ] [\"@I]@\" ? \"@0@\" ?]* | 0"  , NULL, NULL);
+    }
+    return fsm_copy(rb->ITape);
+}
+
+struct fsm *rewrite_cp_markup(struct rewrite_batch *rb, struct fsm *upper, struct fsm *lower1, struct fsm *lower2, int rule_number) {
+    /* Same as rewrite_cp, could be consolidated */
+    struct fsm *Aligned, *threetape, *rulenumtape;
+    /* define CP(X,Y) Tape23of3(Align2(X,Y)) & [ "@I[@"  ? ? ["@I@" ? ?]* "@I]@" ? ? | "@I[]@" ? ? | 0 ] */
+    Aligned = rewrite_align_markup(upper, lower1, lower2);
+    Aligned = rewrite_tape_m_to_n_of_k(Aligned, 3, 4, 4);
+    threetape = fsm_minimize(fsm_intersect(Aligned, rewrite_itape(rb)));
+    rulenumtape = rewrite_tape_m_to_n_of_k(fsm_minimize(fsm_kleene_star(fsm_symbol(rb->namestrings[rule_number-1]))), 2, 2, 4);
+    return fsm_minimize(fsm_intersect(threetape, rulenumtape));
+}
+
+struct fsm *rewrite_cp_transducer(struct rewrite_batch *rb, struct fsm *t, int rule_number) {
+    struct fsm *Aligned, *threetape, *rulenumtape;
+    Aligned = fsm_flatten(t, fsm_symbol("@0@"));
+    Aligned = rewrite_tape_m_to_n_of_k(Aligned, 3, 4, 4);
+    threetape = fsm_minimize(fsm_intersect(Aligned, rewrite_itape(rb)));
+    rulenumtape = rewrite_tape_m_to_n_of_k(fsm_minimize(fsm_kleene_star(fsm_symbol(rb->namestrings[rule_number-1]))), 2, 2, 4);
+    return fsm_minimize(fsm_intersect(threetape, rulenumtape));
+}
+
+struct fsm *rewrite_cp(struct rewrite_batch *rb, struct fsm *upper, struct fsm *lower, int rule_number) {
+    struct fsm *Aligned, *threetape, *rulenumtape;
+    /* define CP(X,Y) Tape23of3(Align2(X,Y)) & [ "@I[@"  ? ? ["@I@" ? ?]* "@I]@" ? ? | "@I[]@" ? ? | 0 ] */
+    Aligned = rewrite_align(upper, lower);
+    Aligned = rewrite_tape_m_to_n_of_k(Aligned, 3, 4, 4);
+    threetape = fsm_minimize(fsm_intersect(Aligned, rewrite_itape(rb)));
+    rulenumtape = rewrite_tape_m_to_n_of_k(fsm_minimize(fsm_kleene_star(fsm_symbol(rb->namestrings[rule_number-1]))), 2, 2, 4);
+    return fsm_minimize(fsm_intersect(threetape, rulenumtape));
+}
+
+void rewrite_add_special_syms(struct rewrite_batch *rb, struct fsm *net) {
+    int i;
+    if (net == NULL)
+        return;
+    sigma_substitute(".#.", "@#@", net->sigma); /* We convert boundaries to our interal rep.                          */
+                                                /* This is because sigma merging (fsm_merge_sigma()) is handled       */
+                                                /* in a special way for .#., which we don't want here.                */
+
+    for (i = 0; specialsymbols[i] != NULL; i++) {
+	if (sigma_find(specialsymbols[i], net->sigma) == -1)
+	    sigma_add(specialsymbols[i], net->sigma);
+    }
+    for (i = 1; i <= rb->num_rules; i++) {
+	sigma_add(rb->namestrings[i-1], net->sigma);
+    }
+    sigma_sort(net);
+}
+
+
+void fsm_clear_contexts(struct fsmcontexts *contexts) {
+    struct fsmcontexts *c, *cp;
+    for (c = contexts; c != NULL; c = cp) {
+	fsm_destroy(c->left);
+	fsm_destroy(c->right);
+	fsm_destroy(c->cpleft);
+	fsm_destroy(c->cpright);
+	cp = c->next;
+	xxfree(c);
+    }
+}
+
+
+struct fsm *rewr_context_restrict(struct rewrite_batch *rb, struct fsm *X, struct fsmcontexts *LR) {
+
+    struct fsm *Var, *Notvar, *UnionL, *UnionP, *Result, *NewX, *Left, *Right;
+    struct fsmcontexts *pairs;
+
+    Var = fsm_symbol("@VARX@");
+    //Notvar = fsm_minimize(fsm_kleene_star(fsm_term_negation(fsm_symbol("@VARX@"))));
+    Notvar = fsm_minus(rewrite_any_4tape(rb), fsm_contains(fsm_symbol("@VARX@")));
+    /* We add the variable symbol to all alphabets to avoid ? matching it */
+    /* which would cause extra nondeterminism */
+
+    NewX = fsm_copy(X);
+    if (sigma_find("@VARX@", NewX->sigma) == -1) {
+	sigma_add("@VARX@", NewX->sigma);
+	sigma_sort(NewX);
+    }
+    UnionP = fsm_empty_set();
+
+    for (pairs = LR; pairs != NULL ; pairs = pairs->next) {
+	if (pairs->left == NULL) {
+	    Left = fsm_empty_string();
+	} else {
+	    Left = fsm_copy(pairs->cpleft);
+	    sigma_add("@VARX@", Left->sigma);
+	    sigma_sort(Left);
+	}
+	if (pairs->right == NULL) {
+	    Right = fsm_empty_string();
+	} else {
+	    Right = fsm_copy(pairs->cpright);
+	    sigma_add("@VARX@", Right->sigma);
+	    sigma_sort(Right);
+	}
+        UnionP = fsm_union(fsm_concat(Left, fsm_concat(fsm_copy(Var), fsm_concat(fsm_copy(Notvar), fsm_concat(fsm_copy(Var), Right)))), UnionP);
+    }
+    UnionL = fsm_concat(fsm_copy(Notvar), fsm_concat(fsm_copy(Var), fsm_concat(fsm_copy(NewX), fsm_concat(fsm_copy(Var), fsm_copy(Notvar)))));
+    Result = fsm_minus(UnionL, fsm_concat(fsm_copy(Notvar), fsm_concat(fsm_copy(UnionP), fsm_copy(Notvar))));
+
+    if (sigma_find("@VARX@", Result->sigma) != -1) {
+        Result = fsm_complement(fsm_substitute_symbol(Result, "@VARX@","@_EPSILON_SYMBOL_@"));
+    } else {
+        Result = fsm_complement(Result);
+    }
+    fsm_destroy(UnionP);
+    fsm_destroy(Var);
+    fsm_destroy(Notvar);
+    fsm_destroy(NewX);
+    return(Result);
+}
+
+struct fsm *rewrite_epextend(struct rewrite_batch *rb) {
+
+    struct fsm *one, *two, *allzeroupper, *threea, *threeb, *threec, *three;
+
+    /* 1.  @O@   @0@     [ANY|@#@] @ID@           */
+    /* 2.  @I[]@ @#Rule@ [ANY]     [@ID@|@0@|ANY] */
+    /* 3a. @I[@  @#Rule@ [ANY]     [@ID@|@0@|ANY] */
+    /* 3b. @I@   @#Rule@ [ANY]     [@ID@|@0@|ANY] */
+    /* 3c. @I]@  @#Rule@ [ANY]     [@ID@|@0@|ANY] */
+    /* 3.  [3a|3b|3c] & ~[[? ? "@0@" ?]*]         */
+
+    /* TODO lower version as well */
+
+    if (rb->Epextend == NULL) {
+	one = fsm_minimize(fsm_concat(fsm_symbol("@O@"), fsm_concat(fsm_symbol("@0@"), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@#@")), fsm_symbol("@ID@")))));
+	two = fsm_minimize(fsm_concat(fsm_symbol("@I[]@"), fsm_concat(fsm_copy(rb->Rulenames), fsm_concat(fsm_copy(rb->ANY), fsm_union(fsm_symbol("@0@"), fsm_union(fsm_symbol("@ID@"), fsm_copy(rb->ANY)))))));
+	allzeroupper = fsm_parse_regex("~[[? ? \"@0@\" ?]*]", NULL, NULL);
+	threea = fsm_minimize(fsm_concat(fsm_symbol("@I[@"), fsm_concat(fsm_copy(rb->Rulenames), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@0@")), fsm_union(fsm_symbol("@0@"), fsm_union(fsm_symbol("@ID@"), fsm_copy(rb->ANY)))))));
+	threeb = fsm_minimize(fsm_kleene_star(fsm_concat(fsm_symbol("@I@"), fsm_concat(fsm_copy(rb->Rulenames), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@0@")), fsm_union(fsm_symbol("@0@"), fsm_union(fsm_symbol("@ID@"), fsm_copy(rb->ANY))))))));
+	threec = fsm_minimize(fsm_concat(fsm_symbol("@I]@"), fsm_concat(fsm_copy(rb->Rulenames), fsm_concat(fsm_union(fsm_copy(rb->ANY), fsm_symbol("@0@")), fsm_union(fsm_symbol("@0@"), fsm_union(fsm_symbol("@ID@"), fsm_copy(rb->ANY)))))));
+	three = fsm_intersect(allzeroupper, fsm_concat(threea, fsm_concat(threeb, threec)));
+	rb->Epextend = fsm_minimize(fsm_union(fsm_union(one, two), three));
+    }
+    return fsm_copy(rb->Epextend);
+}
diff --git a/back-ends/foma/cpp-version/sigma.cc b/back-ends/foma/cpp-version/sigma.cc
new file mode 100644
index 0000000..47e8e98
--- /dev/null
+++ b/back-ends/foma/cpp-version/sigma.cc
@@ -0,0 +1,432 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2012 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <string.h>
+#include <stdlib.h>
+#include "foma.h"
+
+struct sigma *sigma_remove(char *symbol, struct sigma *sigma) {
+  struct sigma *sigma_start, *sigma_prev = NULL;
+  sigma_prev = NULL;
+  sigma_start = sigma;
+  for ( ; sigma != NULL && sigma->number != -1; sigma_prev = sigma, sigma=sigma->next) {
+    if (strcmp(sigma->symbol,symbol) == 0) {
+      if (sigma_prev == NULL) {
+	sigma_start = sigma->next;
+	xxfree(sigma->symbol);
+	xxfree(sigma);
+      } else {
+	(sigma_prev)->next = sigma->next;
+	xxfree(sigma->symbol);
+	xxfree(sigma);
+      }
+      break;
+    }
+  }
+  return(sigma_start);
+}
+
+struct sigma *sigma_remove_num(int num, struct sigma *sigma) {
+  struct sigma *sigma_start, *sigma_prev = NULL;
+  sigma_prev = NULL;
+  sigma_start = sigma;
+  for ( ; sigma != NULL && sigma->number != -1; sigma_prev = sigma, sigma=sigma->next) {
+    if (sigma->number == num) {
+      if (sigma_prev == NULL) {
+	sigma_start = sigma->next;
+	xxfree(sigma->symbol);
+	xxfree(sigma);
+      } else {
+	(sigma_prev)->next = sigma->next;
+	xxfree(sigma->symbol);
+	xxfree(sigma);
+      }
+      break;
+    }
+  }
+  return(sigma_start);
+}
+
+int sigma_add_special (int symbol, struct sigma *sigma) {
+    struct sigma *sigma_previous = NULL, *sigma_splice = NULL;
+    char *str = NULL;
+    if (symbol == EPSILON)
+        str = xxstrdup("@_EPSILON_SYMBOL_@");
+    if (symbol == IDENTITY)
+        str = xxstrdup("@_IDENTITY_SYMBOL_@");
+    if (symbol == UNKNOWN)
+        str = xxstrdup("@_UNKNOWN_SYMBOL_@");
+
+    /* Insert special symbols pre-sorted */
+    if (sigma->number == -1) {
+      sigma->number = symbol;
+    } else {
+        for (;(sigma != NULL) && (sigma->number < symbol) && (sigma->number!=-1); sigma_previous=sigma,sigma = sigma->next) {
+      }
+      sigma_splice = (struct sigma *)xxmalloc(sizeof(struct sigma));
+      if (sigma_previous != NULL) {
+	(sigma_previous)->next = sigma_splice;
+	sigma_splice->number = symbol;
+	sigma_splice->symbol = str;
+	(sigma_splice)->next = sigma;
+	return(symbol);
+      } else {
+	sigma_splice->symbol = sigma->symbol;
+	sigma_splice->number = sigma->number;
+	sigma_splice->next = sigma->next;
+	sigma->number = symbol;
+	sigma->symbol = str;
+	sigma->next = sigma_splice;
+	return(symbol);
+      }
+    }
+    sigma->next = NULL;
+    sigma->symbol = str;
+    return(symbol);
+}
+
+/* WARNING: this function will indeed add a symbol to sigma */
+/* but it's up to the user to sort the sigma (affecting arc numbers in the network) */
+/* before merge_sigma() is ever called */
+
+int sigma_add (char *symbol, struct sigma *sigma) {
+  int assert = -1;
+  struct sigma *sigma_previous = NULL, *sigma_splice = NULL;
+
+  /* Special characters */
+  if (strcmp(symbol, "@_EPSILON_SYMBOL_@") == 0)
+    assert = EPSILON;
+  if (strcmp(symbol,"@_IDENTITY_SYMBOL_@") == 0)
+    assert = IDENTITY;
+  if (strcmp(symbol,"@_UNKNOWN_SYMBOL_@") == 0)
+    assert = UNKNOWN;
+
+  /* Insert non-special in any order */
+  if (assert == -1) {
+    if (sigma->number == -1) {
+ 	sigma->number = 3;
+    } else {
+      for (; sigma->next != NULL; sigma = sigma->next) {
+      }
+      sigma->next = (struct sigma *)xxmalloc(sizeof(struct sigma));
+      if ((sigma->number)+1 < 3) {
+	(sigma->next)->number = 3;
+      } else {
+	(sigma->next)->number = (sigma->number)+1;
+      }
+      sigma = sigma->next;
+    }
+    sigma->next = NULL;
+    sigma->symbol = xxstrdup(symbol);
+    return(sigma->number);
+  } else {
+    /* Insert special symbols pre-sorted */
+    if (sigma->number == -1) {
+      sigma->number = assert;
+    } else {
+      for (;(sigma != NULL) && (sigma->number < assert) && (sigma->number!=-1); sigma_previous=sigma,sigma = sigma->next) {
+      }
+      sigma_splice = (struct sigma *)xxmalloc(sizeof(struct sigma));
+      if (sigma_previous != NULL) {
+	(sigma_previous)->next = sigma_splice;
+	sigma_splice->number = assert;
+	sigma_splice->symbol = (char *)xxmalloc(sizeof(char)*(strlen(symbol)+1));
+	strcpy(sigma_splice->symbol, symbol);
+	(sigma_splice)->next = sigma;
+	return(assert);
+      } else {
+	sigma_splice->symbol = sigma->symbol;
+	sigma_splice->number = sigma->number;
+	sigma_splice->next = sigma->next;
+	sigma->number = assert;
+	sigma->symbol = (char *)xxmalloc(sizeof(char)*(strlen(symbol)+1));
+	strcpy(sigma->symbol, symbol);
+	sigma->next = sigma_splice;
+	return(assert);
+      }
+    }
+    sigma->next = NULL;
+    sigma->symbol = xxstrdup(symbol);
+    return(assert);
+  }
+}
+
+/* Remove symbols that are never used from sigma and renumber   */
+/* The variable force controls whether to remove even though    */
+/* @ or ? is present                                            */
+/* If force == 1, unused symbols are always removed regardless  */
+
+void sigma_cleanup (struct fsm *net, int force) {
+    int i,j,first,maxsigma,*attested;
+    struct fsm_state *fsm;
+    struct sigma *sig, *sig_prev, *sign;
+    
+    if (force == 0) {
+        if (sigma_find_number(IDENTITY, net->sigma) != -1)
+            return;
+        if (sigma_find_number(UNKNOWN, net->sigma) != -1)
+            return;
+    }
+
+    maxsigma = sigma_max(net->sigma);
+    if (maxsigma < 0) { return; }
+    attested = (int *)xxmalloc(sizeof(int)*(maxsigma+1));
+    for (i=0; i<=maxsigma; i++)
+        *(attested+i) = 0;
+    fsm = net->states;
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->in >=0)
+            *(attested+(fsm+i)->in) = 1;
+        if ((fsm+i)->out >=0)
+            *(attested+(fsm+i)->out) = 1;
+    }
+    for (i=3,j=3; i<=maxsigma;i++ ) {
+        if (*(attested+i)) {
+            *(attested+i) = j;
+            j++;
+        }
+    }
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->in > 2)
+            (fsm+i)->in = *(attested+(fsm+i)->in);
+        if ((fsm+i)->out > 2)
+            (fsm+i)->out = *(attested+(fsm+i)->out);
+    }
+    sig_prev = NULL;
+    for (sig = net->sigma; sig != NULL && sig->number != -1; sig = sign) {
+        first = 1;
+	sign = sig->next;
+        if (!*(attested+(sig->number))) {
+	    xxfree(sig->symbol);
+	    xxfree(sig);
+            if (sig_prev != NULL) {
+                sig_prev->next = sign;
+                first = 0;
+            } else {
+                first = 0;
+                net->sigma = sign;
+            }
+        } else {
+            sig->number = sig->number >= 3 ? *(attested+(sig->number)) : sig->number;
+        }
+        if (first)
+            sig_prev = sig;
+    }
+    xxfree(attested);
+    return;
+}
+
+int sigma_max(struct sigma *sigma) {
+  int i;
+  if (sigma == NULL)
+    return -1;
+  for (i=-1; sigma != NULL; sigma = sigma->next)
+      i = sigma->number > i ? sigma->number : i;
+  return(i);
+}
+
+int sigma_size(struct sigma *sigma) {
+  int i;
+  for(i=0; sigma != NULL; sigma = sigma->next)
+    i++;
+  return(i);
+}
+
+struct fsm_sigma_list *sigma_to_list(struct sigma *sigma) {
+    struct fsm_sigma_list *sl;
+    struct sigma *s;
+    sl = (struct fsm_sigma_list *)xxcalloc(sigma_max(sigma)+1,sizeof(struct fsm_sigma_list));
+    for (s = sigma; s != NULL && s->number != -1; s = s->next) {
+        (sl+(s->number))->symbol = s->symbol;
+    }
+    return sl;
+}
+
+int sigma_add_number(struct sigma *sigma, char *symbol, int number) {
+    struct sigma *newsigma, *prev_sigma;
+    prev_sigma = NULL;
+    if (sigma->number == -1) {
+        sigma->symbol = xxstrdup(symbol);
+        sigma->number = number;
+        sigma->next = NULL;
+        return(1);
+    }
+    for (newsigma = sigma; newsigma != NULL; newsigma = newsigma->next) {
+        prev_sigma = newsigma;
+    }
+    newsigma = (struct sigma *)xxmalloc(sizeof(struct sigma));
+    newsigma->symbol = xxstrdup(symbol);
+    newsigma->number = number;
+    newsigma->next = NULL;
+    prev_sigma->next = newsigma;
+    return(1);
+}
+
+int sigma_find_number(int number, struct sigma *sigma) {
+    if (sigma == NULL)
+        return -1;
+    if (sigma->number == -1) {
+        return -1;
+    }
+    /* for (;(sigma != NULL) && (sigma->number <= number); sigma = sigma->next) { */
+    for (;(sigma != NULL) && (sigma->number != -1); sigma = sigma->next) {
+        if (number == sigma->number) {
+            return (sigma->number);
+        }
+    }
+    return -1;
+}
+char *sigma_string(int number, struct sigma *sigma) {
+    if (sigma == NULL)
+        return NULL;
+    if (sigma->number == -1) {
+        return NULL;
+    }
+    for (;(sigma != NULL) && (sigma->number != -1); sigma = sigma->next) {
+        if (number == sigma->number) {
+            return (sigma->symbol);
+        }
+    }
+    return NULL;
+}
+
+/* Substitutes string symbol for sub in sigma */
+/* no check for duplicates                    */
+int sigma_substitute(char *symbol, char *sub, struct sigma *sigma) {
+    if (sigma->number == -1) {
+        return -1;
+    }
+    for (; sigma != NULL && sigma->number != -1 ; sigma = sigma->next) {
+        if (strcmp(sigma->symbol, symbol) == 0) {
+	    xxfree(sigma->symbol);
+	    sigma->symbol = xxstrdup(sub);
+            return(sigma->number);
+        }
+    }
+    return -1;
+}
+
+int sigma_find(char *symbol, struct sigma *sigma) {
+    
+    if (sigma == NULL || sigma->number == -1) {
+        return -1;
+    }
+    for (; sigma != NULL && sigma->number != -1 ; sigma = sigma->next) {
+        if (strcmp(sigma->symbol, symbol) == 0) {
+            return (sigma->number);
+        }
+    }
+    return -1;
+}
+
+struct ssort {
+  char *symbol;
+  int number;
+};
+
+#ifdef ORIGINAL
+int ssortcmp(struct ssort *a, struct ssort *b) {
+  return(strcmp(a->symbol, b->symbol));
+}
+#else
+  int ssortcmp(const void *a, const void *b) {
+    return(strcmp(((struct ssort*)a)->symbol, ((struct ssort*)b)->symbol));
+  }
+#endif
+
+struct sigma *sigma_copy(struct sigma *sigma) {
+    int f = 0;
+    struct sigma *copy_sigma, *copy_sigma_s;
+
+    if (sigma == NULL) { return NULL; }
+    copy_sigma_s = (struct sigma *)xxmalloc(sizeof(struct sigma));
+
+    for (copy_sigma = copy_sigma_s; sigma != NULL; sigma=sigma->next) {
+	if (f == 1) {
+	    copy_sigma->next = (struct sigma *)xxmalloc(sizeof(struct sigma));
+	    copy_sigma = copy_sigma->next;
+	}
+	copy_sigma->number = sigma->number;
+	if (sigma->symbol != NULL)
+	    copy_sigma->symbol = xxstrdup(sigma->symbol);
+	else
+	    copy_sigma->symbol = NULL;
+	copy_sigma->next = NULL;
+	f = 1;
+    }
+    return(copy_sigma_s);
+}
+
+/* Assigns a consecutive numbering to symbols in sigma > IDENTITY */
+/* and sorts the sigma based on the symbol string contents        */
+
+int sigma_sort(struct fsm *net) {
+#ifdef ORIGINAL
+  int(*comp)() = ssortcmp;
+#else
+  int(*comp)(const void*, const void*) = ssortcmp;
+#endif
+  int size, i, max, *replacearray;
+  struct ssort *ssort;
+  struct sigma *sigma;
+  struct fsm_state *fsm_state;
+  
+  size = sigma_max(net->sigma);
+  if (size < 0) { return 1; }
+  ssort = (struct ssort *)xxmalloc(sizeof(struct ssort)*size);
+
+  for (i=0, sigma=net->sigma; sigma != NULL; sigma=sigma->next) {
+    if (sigma->number > IDENTITY) {
+      ssort[i].symbol = (char *)sigma->symbol;
+      ssort[i].number = sigma->number;
+      i++;
+    }
+  }
+  max = i;
+  qsort(ssort, max, sizeof(struct ssort), comp);
+  replacearray = (int *)xxmalloc(sizeof(int)*(size+3));
+  for (i=0; i<max; i++)
+      replacearray[(ssort+i)->number] = i+3;
+
+  /* Replace arcs */
+  for(i=0, fsm_state = net->states; (fsm_state+i)->state_no != -1; i++) {
+    if ((fsm_state+i)->in > IDENTITY)
+      (fsm_state+i)->in = replacearray[(fsm_state+i)->in];
+    if ((fsm_state+i)->out > IDENTITY)
+      (fsm_state+i)->out = replacearray[(fsm_state+i)->out];
+  }
+  /* Replace sigma */
+  for (i=0, sigma=net->sigma; sigma != NULL; sigma=sigma->next) {
+    if (sigma->number > IDENTITY) {
+      sigma->number = i+3;
+      sigma->symbol = (ssort+i)->symbol;
+      i++;
+    }
+  }
+  xxfree(replacearray);
+  xxfree(ssort);
+  return(1);
+}
+
+struct sigma *sigma_create() {
+  struct sigma *sigma;
+  sigma = (struct sigma *)xxmalloc(sizeof(struct sigma));
+  sigma->number = -1; /*Empty sigma*/
+  sigma->next = NULL;
+  sigma->symbol = NULL;
+  return(sigma);
+}
diff --git a/back-ends/foma/cpp-version/spelling.cc b/back-ends/foma/cpp-version/spelling.cc
new file mode 100644
index 0000000..0bf1bd6
--- /dev/null
+++ b/back-ends/foma/cpp-version/spelling.cc
@@ -0,0 +1,880 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2011 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "foma.h"
+
+#define INITIAL_AGENDA_SIZE 256
+#define INITIAL_HEAP_SIZE 256
+#define INITIAL_STRING_SIZE 256
+#define MED_DEFAULT_LIMIT 4              /* Default max words to find                 */
+#define MED_DEFAULT_CUTOFF 15            /* Default MED cost cutoff                   */
+#define MED_DEFAULT_MAX_HEAP_SIZE 262145 /* By default won't grow heap more than this */
+ 
+#define BITMASK(b) (1 << ((b) & 7))
+#define BITSLOT(b) ((b) >> 3)
+#define BITSET(a,b) ((a)[BITSLOT(b)] |= BITMASK(b))
+#define BITCLEAR(a,b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
+#define BITTEST(a,b) ((a)[BITSLOT(b)] & BITMASK(b))
+#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)
+#define min_(X, Y)  ((X) < (Y) ? (X) : (Y))
+
+static int calculate_h(struct apply_med_handle *medh, int *intword, int currpos, int state);
+static struct apply_med_handle::astarnode *node_delete_min(struct apply_med_handle*);
+int node_insert(struct apply_med_handle *medh, int wordpos, int fsmstate, int g, int h, int in, int out, int parent);
+
+char *print_sym(int sym, struct sigma *sigma) {
+    while (sigma != NULL) {
+        if (sigma->number == sym) {
+	    return(sigma->symbol);
+        }
+        sigma = sigma->next;
+    }
+    return NULL;
+}
+
+void print_match(struct apply_med_handle *medh, struct apply_med_handle::astarnode *node, struct sigma *sigma, char *word) {
+    int sym, i, wordlen , printptr;
+    struct apply_med_handle::astarnode *n;
+    int_stack_clear();
+    wordlen = medh->wordlen;
+    for (n = node; n != NULL ; n = medh->agenda+(n->parent)) {
+        if (n->in == 0 && n->out == 0)
+            break;
+        if (n->parent == -1)
+            break;
+        int_stack_push(n->in);
+    }
+    printptr = 0;
+    if (medh->outstring_length < 2*wordlen) {
+	medh->outstring_length *= 2;
+	medh->outstring = (char *)xxrealloc(medh->outstring, medh->outstring_length*sizeof(char));
+    }
+    while (!(int_stack_isempty())) {
+        sym = int_stack_pop();
+        if (sym > 2) {
+            printptr += sprintf(medh->outstring+printptr,"%s", print_sym(sym, sigma));
+        }
+        if (sym == 0) {
+	    if (medh->align_symbol) {
+		printptr += sprintf(medh->outstring+printptr,"%s",medh->align_symbol);
+	    }
+        }
+        if (sym == 2) {
+            printptr += sprintf(medh->outstring+printptr,"@");
+        }
+    }
+    for (n = node; n != NULL ; n = medh->agenda+(n->parent)) {
+        if (n->in == 0 && n->out == 0)
+            break;
+        if (n->parent == -1)
+            break;
+        else
+            int_stack_push(n->out);
+    }
+    printptr = 0;
+    if (medh->instring_length < 2*wordlen) {
+	medh->instring_length *= 2;
+	medh->instring = (char *)xxrealloc(medh->instring, medh->instring_length*sizeof(char));
+    }
+    for (i = 0; !(int_stack_isempty()); ) {
+        sym = int_stack_pop();
+        if (sym > 2) {
+            printptr += sprintf(medh->instring+printptr,"%s", print_sym(sym, sigma));
+            i += utf8skip(word+i)+1;
+        }
+        if (sym == 0) {
+	    if (medh->align_symbol) {
+		printptr += sprintf(medh->instring+printptr,"%s",medh->align_symbol);
+	    }
+        }
+        if (sym == 2) {
+            if (i > wordlen) {
+		printptr += sprintf(medh->instring+printptr,"*");
+            } else {
+		//printf("%.*s", utf8skip(word+i)+1, word+i);
+		printptr += sprintf(medh->instring+printptr,"%.*s", utf8skip(word+i)+1, word+i);
+                i+= utf8skip(word+i)+1;
+            }
+        }
+    }
+    medh->cost = node->g;
+    // printf("Cost[f]: %i\n\n", node->g);
+}
+
+void apply_med_clear(struct apply_med_handle *medh) {
+    if (medh == NULL)
+	return;
+    if (medh->agenda != NULL)
+	xxfree(medh->agenda);
+    if (medh->instring != NULL)
+	xxfree(medh->instring);
+    if (medh->outstring != NULL)
+	xxfree(medh->outstring);
+    if (medh->heap != NULL)
+	xxfree(medh->heap);
+    if (medh->state_array != NULL)
+	xxfree(medh->state_array);
+    if (medh->align_symbol != NULL)
+	xxfree(medh->align_symbol);
+    if (medh->letterbits != NULL)
+	xxfree(medh->letterbits);
+    if (medh->nletterbits != NULL)
+	xxfree(medh->nletterbits);
+    if (medh->intword != NULL)
+	xxfree(medh->intword);
+    if (medh->sigmahash != NULL)
+	sh_done(medh->sigmahash);
+    xxfree(medh);
+}
+
+struct apply_med_handle *apply_med_init(struct fsm *net) {
+
+    struct apply_med_handle *medh;
+    struct sigma *sigma;
+    medh = (struct apply_med_handle *)xxcalloc(1,sizeof(struct apply_med_handle));
+    medh->net = net;
+    medh->agenda = (struct apply_med_handle::astarnode *)xxmalloc(sizeof(struct apply_med_handle::astarnode)*INITIAL_AGENDA_SIZE);
+    medh->agenda->f = -1;
+    medh->agenda_size = INITIAL_AGENDA_SIZE;
+    
+    medh->heap = (int *)xxmalloc(sizeof(int)*INITIAL_HEAP_SIZE);
+    medh->heap_size = INITIAL_HEAP_SIZE;
+    *(medh->heap) = 0; /* Points to sentinel */
+    medh->astarcount = 1;
+    medh->heapcount = 0;
+    medh->state_array = map_firstlines(net);
+    if (net->medlookup != NULL && net->medlookup->confusion_matrix != NULL) {
+	medh->hascm = 1;
+	medh->cm = net->medlookup->confusion_matrix;
+    }
+    medh->maxsigma = sigma_max(net->sigma)+1;
+    medh->sigmahash = sh_init();
+    for (sigma = net->sigma; sigma != NULL && sigma->number != -1 ; sigma=sigma->next ) {
+	if (sigma->number > IDENTITY) {
+	    sh_add_string(medh->sigmahash, sigma->symbol, sigma->number);
+	}
+    }
+
+
+    fsm_create_letter_lookup(medh, net);
+
+    medh->instring = (char *)xxmalloc(sizeof(char)*INITIAL_STRING_SIZE);
+    medh->instring_length = INITIAL_STRING_SIZE;
+    medh->outstring = (char *)xxmalloc(sizeof(char)*INITIAL_STRING_SIZE);
+    medh->outstring_length = INITIAL_STRING_SIZE;
+    
+    medh->med_limit = MED_DEFAULT_LIMIT;
+    medh->med_cutoff = MED_DEFAULT_CUTOFF;
+    medh->med_max_heap_size = MED_DEFAULT_MAX_HEAP_SIZE;
+    return(medh);
+}
+
+void apply_med_set_heap_max(struct apply_med_handle *medh, int max) {
+    if (medh != NULL) {
+	medh->med_max_heap_size = max;
+    }
+}
+
+void apply_med_set_align_symbol(struct apply_med_handle *medh, char *align) {
+    if (medh != NULL) {
+	medh->align_symbol = xxstrdup(align);
+    }
+}
+
+void apply_med_set_med_limit(struct apply_med_handle *medh, int max) {
+    if (medh != NULL) {
+	medh->med_limit = max;
+    }
+}
+
+void apply_med_set_med_cutoff(struct apply_med_handle *medh, int max) {
+    if (medh != NULL) {
+	medh->med_cutoff = max;
+    }
+}
+
+int apply_med_get_cost(struct apply_med_handle *medh) {
+    return(medh->cost);
+}
+
+char *apply_med_get_instring(struct apply_med_handle *medh) {
+    return(medh->instring);
+}
+
+char *apply_med_get_outstring(struct apply_med_handle *medh) {
+    return(medh->outstring);
+}
+
+char *apply_med(struct apply_med_handle *medh, char *word) {
+
+    /* local ok: i, j, target, in, out, g, h, curr_node                                   */
+    /* not ok: curr_ptr, curr_pos, lines, nummatches, nodes_expanded, curr_state           */
+
+    int i, j, target, in, out, g, h, thisskip;
+
+    int delcost, subscost, inscost;
+    char temputf[5] ;
+
+    struct apply_med_handle::astarnode *curr_node;
+
+    delcost = subscost = inscost = 1;
+
+
+    if (word == NULL) {
+	goto resume;
+    }
+
+    medh->word = word;
+
+    medh->nodes_expanded = 0;
+    medh->astarcount = 1;
+    medh->heapcount = 0;
+
+    medh->wordlen = strlen(word);
+    medh->utf8len = utf8strlen(word);
+    if (medh->intword != NULL) {
+	xxfree(medh->intword);
+    }
+    medh->intword = (int *)xxmalloc(sizeof(int)*(medh->utf8len+1));
+
+   /* intword -> sigma numbers of word */
+    for (i=0, j=0; i < medh->wordlen; i += thisskip, j++) {
+	thisskip = utf8skip(word+i)+1;
+	strncpy(temputf, word+i, thisskip);
+	temputf[thisskip] = '\0';
+	if (sh_find_string(medh->sigmahash, temputf) != NULL) {
+	    *(medh->intword+j) = sh_get_value(medh->sigmahash);
+	} else {
+            *(medh->intword+j) = IDENTITY;
+        }
+    }
+
+    
+
+    *(medh->intword+j) = -1; /* sentinel */
+    
+    /* Insert (0,0) g = 0 */
+    
+    h = calculate_h(medh, medh->intword, 0, 0);
+
+    /* Root node */
+    
+    if (!node_insert(medh,0,0,0,h,0,0,-1)) { goto out; }
+    medh->nummatches = 0;
+
+    for(;;) {
+
+        curr_node = node_delete_min(medh);
+        /* Need to save this in case we realloc and print_match() */
+        medh->curr_agenda_offset = curr_node-medh->agenda;
+        if (curr_node == NULL) {
+	    //printf("Reached cutoff of %i.\n", medh->med_cutoff);
+            goto out;
+        }
+	medh->curr_state = curr_node->fsmstate;
+	medh->curr_ptr = (medh->state_array+medh->curr_state)->transitions;
+	if (!medh->curr_ptr->final_state || !(curr_node->wordpos == medh->utf8len)) {
+	    //continue;
+	}
+
+        medh->nodes_expanded++;
+
+        if (curr_node->f > medh->med_cutoff) {
+            //printf("Reached cutoff of %i\n", medh->med_cutoff);
+            goto out;
+        }
+
+        medh->curr_pos = curr_node->wordpos;
+        medh->curr_state = curr_node->fsmstate;
+        medh->curr_g = curr_node->g;
+        
+        medh->lines = 0;
+        medh->curr_node_has_match = 0;
+
+        for (medh->curr_ptr = (medh->state_array+medh->curr_state)->transitions ; ;) {
+            if (medh->curr_ptr->state_no == -1) {
+                break;
+            }
+            medh->lines++;
+            if (medh->curr_ptr->final_state && medh->curr_pos == medh->utf8len) {
+                if (medh->curr_node_has_match == 0) {
+                    /* Found a match */
+                    medh->curr_node_has_match = 1;
+                    print_match(medh, medh->agenda+medh->curr_agenda_offset, medh->net->sigma, medh->word);
+                    medh->nummatches++;
+		    return(medh->outstring);
+                }
+            }
+
+	resume:
+
+	    if (medh->nummatches == medh->med_limit) {
+		goto out;
+	    }
+	    
+            if (medh->curr_ptr->target == -1 && medh->curr_pos == medh->utf8len)
+                break;
+            if (medh->curr_ptr->target == -1 && medh->lines == 1)
+                goto insert;
+            if (medh->curr_ptr->target == -1)
+                break;
+
+            target = medh->curr_ptr->target;
+            /* Add nodes to edge:0, edge:input, 0:edge */
+            
+            /* Delete a symbol from input */
+            in = medh->curr_ptr->in;
+            out = 0;
+            g = medh->hascm ? medh->curr_g + *(medh->cm+in*medh->maxsigma) : medh->curr_g + delcost;
+            h = calculate_h(medh, medh->intword, medh->curr_pos, medh->curr_ptr->target);
+
+            if ((medh->curr_pos == medh->utf8len) && (medh->curr_ptr->final_state == 0) && (h == 0)) {
+		// h = 1;
+            }
+
+            if (g+h <= medh->med_cutoff) {
+                if (!node_insert(medh, medh->curr_pos, target, g, h, in, out, medh->curr_agenda_offset)) {
+		    goto out;
+		}
+	    }
+            if (medh->curr_pos == medh->utf8len)
+                goto skip;
+
+            /* Match/substitute */
+            in = medh->curr_ptr->in;
+            out = *(medh->intword+medh->curr_pos);
+            if (in != out) {
+                g = medh->hascm ? medh->curr_g + *(medh->cm+in*medh->maxsigma+out) : medh->curr_g + subscost;
+            } else {
+                g = medh->curr_g;
+            }
+           
+            h = calculate_h(medh, medh->intword, medh->curr_pos+1, medh->curr_ptr->target);
+            if ((g+h) <= medh->med_cutoff) {
+                if (!node_insert(medh,medh->curr_pos+1, target, g, h, in, out, medh->curr_agenda_offset)) {
+		    goto out;
+		}
+            }
+        insert:
+            /* Insert a symbol into input */
+            /* Can only be done once per state */
+
+            if (medh->lines == 1) {
+
+                in = 0;
+                out = *(medh->intword+medh->curr_pos);
+                
+                g = medh->hascm ? medh->curr_g + *(medh->cm+out) : medh->curr_g + inscost;
+                h = calculate_h(medh, medh->intword, medh->curr_pos+1, medh->curr_state);
+                
+                if (g+h <= medh->med_cutoff)
+                    if (!node_insert(medh,medh->curr_pos+1, medh->curr_state, g, h, in, out, medh->curr_agenda_offset)) {
+			goto out;
+		    }
+            }
+            if (medh->curr_ptr->target == -1)
+                break;
+        skip:
+            if ((medh->curr_ptr+1)->state_no == (medh->curr_ptr)->state_no)
+                medh->curr_ptr++;
+            else
+                break;
+        }
+    }
+ out:
+     return(NULL);
+}
+
+int calculate_h(struct apply_med_handle *medh, int *intword, int currpos, int state) {
+    int i, j, hinf, hn, curr_sym;
+    uint8_t *bitptr, *nbitptr;
+    hinf = 0;
+    hn = 0;
+
+    bitptr = state*medh->bytes_per_letter_array + medh->letterbits;
+    nbitptr = state*medh->bytes_per_letter_array + medh->nletterbits;
+
+   /* For n = inf */
+    if (*(intword+currpos) == -1)
+        return 0;
+    for (i = currpos; *(intword+i) != -1; i++) {
+        curr_sym = *(intword+i);
+        if (!BITTEST(bitptr, curr_sym)) {
+            hinf++;
+        }
+    }
+    /* For n = maxdepth */
+    if (*(intword+currpos) == -1)
+        return 0;
+    for (i = currpos, j = 0; j < medh->maxdepth && *(intword+i) != -1; i++, j++) {
+        curr_sym = *(intword+i);
+        if (!BITTEST(nbitptr, curr_sym)) {
+            hn++;
+        }
+    }
+    return(hinf > hn ? hinf : hn);
+}
+
+struct apply_med_handle::astarnode *node_delete_min(struct apply_med_handle *medh) {
+    int i, child;
+    struct apply_med_handle::astarnode *firstptr, *lastptr;
+    if (medh->heapcount == 0) {
+        return NULL;
+    }
+ 
+   /* We find the min from the heap */
+
+    firstptr = medh->agenda+medh->heap[1];
+    lastptr = medh->agenda+medh->heap[medh->heapcount];
+    medh->heapcount--;
+    
+    /* Adjust heap */
+    for (i = 1; (i<<1) <= medh->heapcount; i = child) {
+        child = i<<1;
+        
+        /* If right child is smaller (higher priority) than left child */
+        if (child != medh->heapcount &&
+            ((medh->agenda+medh->heap[child+1])->f < (medh->agenda+medh->heap[child])->f ||
+             ((medh->agenda+medh->heap[child+1])->f <= (medh->agenda+medh->heap[child])->f &&
+              (medh->agenda+medh->heap[child+1])->wordpos > (medh->agenda+medh->heap[child])->wordpos))) {
+            child++;
+        }
+        
+        /* If child has lower priority than last element */
+        if ((medh->agenda+medh->heap[child])->f < lastptr->f ||
+            ((medh->agenda+medh->heap[child])->f <= lastptr->f &&
+             (medh->agenda+medh->heap[child])->wordpos > lastptr->wordpos)) {
+            
+            medh->heap[i] = medh->heap[child];
+        } else {
+            break;
+        }
+    }
+    medh->heap[i] = (lastptr-medh->agenda);
+    return(firstptr);
+}
+
+int node_insert(struct apply_med_handle *medh, int wordpos, int fsmstate, int g, int h, int in, int out, int parent) {
+    int i,j,f;
+    /* We add the node in the array */
+    i = medh->astarcount;
+    if (i >= (medh->agenda_size-1)) {
+	if (medh->agenda_size*2 >= medh->med_max_heap_size) {
+	    //printf("heap limit reached by %i\n", medh->med_max_heap_size);
+	    return 0;
+	}
+        medh->agenda_size *= 2;
+        medh->agenda = (struct apply_med_handle::astarnode *)xxrealloc(medh->agenda, sizeof(struct apply_med_handle::astarnode)*medh->agenda_size);
+    }
+    f = g + h;
+    (medh->agenda+i)->wordpos = wordpos;
+    (medh->agenda+i)->fsmstate = fsmstate;
+    (medh->agenda+i)->f = f;
+    (medh->agenda+i)->g = g;
+    (medh->agenda+i)->h = h;
+    (medh->agenda+i)->in = in;
+    (medh->agenda+i)->out = out;
+    (medh->agenda+i)->parent = parent;
+    medh->astarcount++;
+
+    /* We also put the ptr on the heap */
+    medh->heapcount++;
+
+    if (medh->heapcount == medh->heap_size-1) {
+        medh->heap = (int *)xxrealloc(medh->heap, sizeof(int)*medh->heap_size*2);
+        medh->heap_size *= 2;
+    }
+    /*                                     >= makes fifo */
+    // for (j = heapcount; (agenda+heap[j/2])->f > f; j /= 2) {
+    for (j = medh->heapcount; ( (medh->agenda+medh->heap[j>>1])->f > f) || ((medh->agenda+medh->heap[j>>1])->f >= f && (medh->agenda+medh->heap[j>>1])->wordpos <= wordpos) ; j = j >> 1) {
+        medh->heap[j] = medh->heap[j>>1];
+    }
+    medh->heap[j] = i;
+    return 1;
+}
+
+
+void letterbits_union(int v, int vp, uint8_t *ptr, int bytes_per_letter_array) {
+    int i;
+    uint8_t *vptr, *vpptr;
+    vptr = ptr+(v*bytes_per_letter_array);
+    vpptr = ptr+(vp*bytes_per_letter_array);
+    for (i=0; i < bytes_per_letter_array; i++) {
+        *(vptr+i) = *(vptr+i)|*(vpptr+i);
+    }
+}
+
+void letterbits_copy(int source, int target, uint8_t *ptr, int bytes_per_letter_array) {
+    int i;
+    uint8_t  *sourceptr, *targetptr;
+    sourceptr = ptr+(source*bytes_per_letter_array);
+    targetptr = ptr+(target*bytes_per_letter_array);
+    for (i=0; i < bytes_per_letter_array; i++) {
+        *(targetptr+i) = *(sourceptr+i);
+    }
+}
+
+void letterbits_add(int v, int symbol, uint8_t *ptr, int bytes_per_letter_array) {
+    uint8_t *vptr;
+    vptr = ptr+(v*bytes_per_letter_array);
+    BITSET(vptr, symbol);
+}
+
+/* Creates, for each state, a list of symbols that can be matched             */
+/* somewhere in subsequent paths (the case n = inf)                           */
+/* This is needed for h() of A*-search in approximate matching                */
+/* This is done by a DFS where each state gets the properties                 */
+/* of the arcs it has as well as a copy of the properties of the target state */
+/* At the same time we keep track of the strongly connected components        */
+/* And copy the properties from each root of the SCC to the children          */
+/* The SCC part is required for the algorithm to work with cyclic graphs      */
+/* This is basically a modification of Tarjan's (1972) SCC algorithm          */
+/* However, it's converted from recursive form to iterative form using        */
+/* goto statements.  Here's the original recursive specification:             */
+
+/* Input: FSM = (V,E)                                                        */
+/* Output: bitvector v.letters for each state                                */
+/* index = 1                                    DFS node number counter      */
+
+/* procedure Mark(v)                                                         */
+/*   v.index = index                            Set the depth index for v    */
+/*   v.lowlink = index                                                       */
+/*   index++                                                                 */
+/*   push(v)                                    Push v on the stack          */
+/*   forall edge = (v, v') in E do              Consider successors of v     */
+/*     v.letters |= v'.letters | edge           Copy target v'.letters       */
+/*     if (v'.index == 0)                       Was successor v' visited?    */
+/*       Mark(v')                               Recurse                      */
+/*       v.lowlink = min(v.lowlink, v'.lowlink)                              */
+/*     elseif (v' is on stack)                  Was successor v' in stack S? */
+/*       v.lowlink = min(v.lowlink, v'.index)                                */
+/*   if (v.lowlink == v.index)                  Is v the root of a SCC?      */
+/*     do                                                                    */
+/*       pop(v')                                                             */
+/*       v'.letters = v.letters                                              */
+/*     while (v' != v)                                                       */
+
+/* For keeping track of the strongly connected components */
+/* when doing the DFS                                     */
+
+struct sccinfo {
+    int index;
+    int lowlink;
+    int on_t_stack;
+};
+
+void fsm_create_letter_lookup(struct apply_med_handle *medh, struct fsm *net) {
+
+    int num_states, num_symbols, index, v, vp, copystate, i, j;
+    struct fsm_state *curr_ptr;
+    struct sccinfo *sccinfo;
+    int depth;
+    medh->maxdepth = 2;
+
+    num_states = net->statecount;
+    num_symbols = sigma_max(net->sigma);
+    
+    medh->bytes_per_letter_array = BITNSLOTS(num_symbols+1);
+    medh->letterbits = (uint8_t *)xxcalloc(medh->bytes_per_letter_array*num_states,sizeof(uint8_t));
+    medh->nletterbits = (uint8_t *)xxcalloc(medh->bytes_per_letter_array*num_states,sizeof(uint8_t));
+
+    sccinfo = (struct sccinfo *)xxcalloc(num_states,sizeof(struct sccinfo));
+    
+    index = 1;
+    curr_ptr = net->states;
+    goto l1;
+
+    /* Here we go again, converting a recursive algorithm to an iterative one */
+    /* by gotos */
+
+    while(!ptr_stack_isempty()) {
+
+        curr_ptr = (struct fsm_state*)ptr_stack_pop();
+
+        v = curr_ptr->state_no; /* source state number */
+        vp = curr_ptr->target;  /* target state number */
+
+        /* T: v.letterlist = list_union(v'->list, current edge label) */
+
+        letterbits_union(v, vp, medh->letterbits,medh->bytes_per_letter_array);         /* add v' target bits to v */
+        letterbits_add(v, curr_ptr->in, medh->letterbits,medh->bytes_per_letter_array); /* add current arc label to v */
+
+        (sccinfo+v)->lowlink = min_((sccinfo+v)->lowlink,(sccinfo+vp)->lowlink);
+
+        if ((curr_ptr+1)->state_no != curr_ptr->state_no) {
+            goto l4;
+        } else {
+            goto l3;
+        }
+        
+    l1:
+        v = curr_ptr->state_no;
+        vp = curr_ptr->target;  /* target */
+        /* T: v.lowlink = index, index++, Tpush(v) */
+        (sccinfo+v)->index = index;
+        (sccinfo+v)->lowlink = index;
+        index++;
+        int_stack_push(v);
+        (sccinfo+v)->on_t_stack = 1;
+        /* if v' not visited (is v'.index set) */
+
+        /* If done here, check lowlink, pop */
+
+        if (vp == -1)
+            goto l4;
+    l2:
+        letterbits_add(v, curr_ptr->in, medh->letterbits,medh->bytes_per_letter_array);
+        if ((sccinfo+vp)->index == 0) {
+            /* push (v,e) ptr on stack */
+            ptr_stack_push(curr_ptr);
+            curr_ptr = (medh->state_array+(curr_ptr->target))->transitions;
+            /* (v,e) = (v',firstedge), goto init */
+            goto l1;
+            /* if v' visited */
+            /* T: v.lowlink = min(v.lowlink, v'.lowlink), union v.list with e, move to next edge in v, goto loop */
+        } else if ((sccinfo+vp)->on_t_stack) {
+            (sccinfo+v)->lowlink = min_((sccinfo+v)->lowlink,(sccinfo+vp)->lowlink);
+        }
+        /* If node is visited, copy its bits */
+        letterbits_union(v,vp,medh->letterbits,medh->bytes_per_letter_array);
+
+    l3:
+        if ((curr_ptr+1)->state_no == curr_ptr->state_no) {
+            curr_ptr++;
+            v = curr_ptr->state_no;
+            vp = curr_ptr->target;  /* target */
+            goto l2;
+        }
+
+        
+        /* T: if lastedge, v.lowlink == v.index, pop Tstack until v is popped and copy v.list to others */
+        /* Copy all bits from root of SCC to descendants */
+    l4:
+        if ((sccinfo+v)->lowlink == (sccinfo+v)->index) {
+            //printf("\nSCC: [%i] ",v);
+            while((copystate = int_stack_pop()) != v) {
+                (sccinfo+copystate)->on_t_stack = 0;
+                letterbits_copy(v, copystate, medh->letterbits, medh->bytes_per_letter_array);
+                //printf("%i ", copystate);
+            }
+            (sccinfo+v)->on_t_stack = 0;
+            //printf("\n");
+        }
+    }
+    
+    for (i=0; i < num_states; i++) {
+        //printf("State %i: ",i);
+        for (j=0; j <= num_symbols; j++) {
+            if (BITTEST(medh->letterbits+(i*medh->bytes_per_letter_array),j)) {
+                //printf("[%i]",j);
+            }
+        }
+        //printf("\n");
+    }
+    int_stack_clear();
+
+    /* We do the same thing for some finite n (up to maxdepth) */
+    /* and store the result in nletterbits                     */
+
+    for (v=0; v < num_states; v++) {
+        ptr_stack_push((medh->state_array+v)->transitions);
+        int_stack_push(0);
+        while (!ptr_stack_isempty()) {
+	    curr_ptr = (struct fsm_state*)ptr_stack_pop();
+            depth = int_stack_pop();
+        looper:
+            if (depth == medh->maxdepth)
+                continue;
+            if (curr_ptr->in != -1) {
+                letterbits_add(v, curr_ptr->in, medh->nletterbits, medh->bytes_per_letter_array);
+            }
+            if (curr_ptr->target != -1) {
+                if (curr_ptr->state_no == (curr_ptr+1)->state_no) {
+                    ptr_stack_push(curr_ptr+1);
+                    int_stack_push(depth);
+                }
+                depth++;
+                curr_ptr = (medh->state_array+(curr_ptr->target))->transitions;
+                goto looper;
+            }
+        }
+    }
+    for (i=0; i < num_states; i++) {
+        //printf("State %i: ",i);
+        for (j=0; j <= num_symbols; j++) {
+            if (BITTEST(medh->nletterbits+(i*medh->bytes_per_letter_array),j)) {
+                //printf("[%i]",j);
+            }
+        }
+        //printf("\n");
+    }
+    xxfree(sccinfo);
+}
+
+void cmatrix_print_att(struct fsm *net, FILE *outfile) {
+    int i, j, *cm, maxsigma;
+    maxsigma = sigma_max(net->sigma) + 1;
+    cm = net->medlookup->confusion_matrix;
+
+
+    for (i = 0; i < maxsigma ; i++) {
+        for (j = 0; j < maxsigma ; j++) {
+            if ((i != 0 && i < 3) || (j != 0 && j < 3)) { continue; }
+            if (i == 0 && j != 0) {
+                fprintf(outfile,"0\t0\t%s\t%s\t%i\n", "@0@", sigma_string(j, net->sigma), *(cm+i*maxsigma+j));
+            } else if (j == 0 && i != 0) {
+                fprintf(outfile,"0\t0\t%s\t%s\t%i\n", sigma_string(i,net->sigma), "@0@", *(cm+i*maxsigma+j));
+            } else if (j != 0 && i != 0) {
+                fprintf(outfile,"0\t0\t%s\t%s\t%i\n", sigma_string(i,net->sigma),sigma_string(j, net->sigma), *(cm+i*maxsigma+j));
+            }
+        }
+    }
+    fprintf(outfile,"0\n");
+}
+
+void cmatrix_print(struct fsm *net) {
+    int lsymbol, i, j, *cm, maxsigma;
+    char *thisstring;
+    struct sigma *sigma;
+    maxsigma = sigma_max(net->sigma) + 1;
+    cm = net->medlookup->confusion_matrix;
+
+    lsymbol = 0 ;
+    for (sigma = net->sigma; sigma != NULL; sigma = sigma->next) {
+        if (sigma->number < 3)
+            continue;
+        lsymbol = strlen(sigma->symbol) > lsymbol ? strlen(sigma->symbol) : lsymbol;
+    }
+    printf("%*s",lsymbol+2,"");
+    printf("%s","0 ");
+
+    for (i = 3; ; i++) {
+        if ((thisstring = sigma_string(i, net->sigma)) != NULL) {
+            printf("%s ",thisstring);
+        } else {
+            break;
+        }
+    }
+
+    printf("\n");
+
+    for (i = 0; i < maxsigma ; i++) {
+        for (j = 0; j < maxsigma ; j++) {
+            if (j == 0) {
+                if (i == 0) {
+                    printf("%*s",lsymbol+1,"0");
+                    printf("%*s",2,"*");
+                } else {
+                    printf("%*s",lsymbol+1, sigma_string(i, net->sigma));
+                    printf("%*d",2,*(cm+i*maxsigma+j));
+                }
+                j++;
+                j++;
+                continue;
+            }
+            if (i == j) {
+                printf("%.*s",(int)strlen(sigma_string(j, net->sigma))+1,"*");
+            } else {
+                printf("%.*d",(int)strlen(sigma_string(j, net->sigma))+1,*(cm+i*maxsigma+j));
+            }
+        }
+        printf("\n");
+        if (i == 0) {
+            i++; i++;
+        }
+    }
+}
+
+void cmatrix_init(struct fsm *net) {
+    int maxsigma, *cm, i, j;
+    if (net->medlookup == NULL) {
+        net->medlookup = (struct medlookup *)xxcalloc(1,sizeof(struct medlookup));
+    }
+    maxsigma = sigma_max(net->sigma)+1;
+    cm = (int *)xxcalloc(maxsigma*maxsigma, sizeof(int));
+    net->medlookup->confusion_matrix = cm;
+    for (i = 0; i < maxsigma; i++) {
+        for (j = 0; j < maxsigma; j++) {
+            if (i == j)
+                *(cm+i*maxsigma+j) = 0;
+            else
+                *(cm+i*maxsigma+j) = 1;
+        }
+    }
+}
+
+void cmatrix_default_substitute(struct fsm *net, int cost) {
+    int i, j, maxsigma, *cm;
+    cm = net->medlookup->confusion_matrix;
+    maxsigma = sigma_max(net->sigma)+1;
+    for (i = 1; i < maxsigma; i++) {
+        for (j = 1; j < maxsigma; j++) {
+            if (i == j) {
+                *(cm+i*maxsigma+j) = 0;
+            } else {
+                *(cm+i*maxsigma+j) = cost;
+            }
+        }
+    }
+}
+
+void cmatrix_default_insert(struct fsm *net, int cost) {
+    int i, maxsigma, *cm;
+    cm = net->medlookup->confusion_matrix;
+    maxsigma = sigma_max(net->sigma)+1;
+    for (i = 0; i < maxsigma; i++) {
+        *(cm+i) = cost;
+    }
+}
+
+void cmatrix_default_delete(struct fsm *net, int cost) {
+    int i, maxsigma, *cm;
+    cm = net->medlookup->confusion_matrix;
+    maxsigma = sigma_max(net->sigma)+1;
+    for (i = 0; i < maxsigma; i++) {
+        *(cm+i*maxsigma) = cost;
+    }
+}
+
+void cmatrix_set_cost(struct fsm *net, char *in, char *out, int cost) {
+    int i, o, maxsigma, *cm;
+    cm = net->medlookup->confusion_matrix;
+    maxsigma = sigma_max(net->sigma) + 1;
+    if (in == NULL) {
+        i = 0;
+    } else {
+        i = sigma_find(in, net->sigma);
+    }
+    if (out == NULL) {
+        o = 0;
+    } else {
+        o = sigma_find(out, net->sigma);
+    }
+    if (i == -1) {
+        printf("Warning, symbol '%s' not in alphabet\n",in);
+        return;
+    }
+    if (o == -1) {
+        printf("Warning, symbol '%s' not in alphabet\n",out);
+        return;
+    }
+    *(cm+i*maxsigma+o) = cost;
+}
diff --git a/back-ends/foma/cpp-version/stack.cc b/back-ends/foma/cpp-version/stack.cc
new file mode 100644
index 0000000..cf0397d
--- /dev/null
+++ b/back-ends/foma/cpp-version/stack.cc
@@ -0,0 +1,221 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2011 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "foma.h"
+
+extern int quiet_mode;
+
+struct stack_entry *main_stack;
+
+int stack_size() {
+  int i;
+  struct stack_entry *stack_ptr;
+  for (i=0, stack_ptr = main_stack; stack_ptr->next != NULL; i++)
+    stack_ptr = stack_ptr->next;
+  return i;
+}
+
+int stack_init() {
+  main_stack = xxmalloc(sizeof(struct stack_entry));
+  main_stack->number = -1;
+  main_stack->fsm = NULL;
+  main_stack->next = NULL;
+  main_stack->previous = NULL;
+  return 1;
+}
+
+int stack_add(struct fsm *fsm) {
+  int i;
+  struct stack_entry *stack_ptr, *stack_ptr_previous;
+  stack_ptr_previous = NULL;
+
+  fsm_count(fsm);
+  if (strcmp(fsm->name,"") == 0)
+      sprintf(fsm->name, "%X",rand());
+  for (i=0, stack_ptr = main_stack; stack_ptr->number != -1; i++) {
+    stack_ptr_previous = stack_ptr;
+    stack_ptr = stack_ptr->next;
+  }
+  stack_ptr->next = xxmalloc(sizeof(struct stack_entry));
+  stack_ptr->fsm = fsm;
+  stack_ptr->ah = NULL;
+  stack_ptr->amedh = NULL;
+  stack_ptr->number = i;
+  stack_ptr->previous = stack_ptr_previous;
+  (stack_ptr->next)->number = -1;
+  (stack_ptr->next)->fsm = NULL;
+  (stack_ptr->next)->next = NULL;
+  (stack_ptr->next)->previous = stack_ptr;
+  if (!quiet_mode)
+      print_stats(fsm);
+  return(stack_ptr->number);
+}
+
+struct apply_med_handle *stack_get_med_ah() {
+    struct stack_entry *se;
+    se = stack_find_top();
+    if (se == NULL) {
+	return(NULL);
+    }
+    if (se->amedh == NULL) {
+	se->amedh = apply_med_init(se->fsm);
+	apply_med_set_align_symbol(se->amedh, "-");
+    }
+    return(se->amedh);
+}
+
+struct apply_handle *stack_get_ah() {
+    struct stack_entry *se;
+    se = stack_find_top();
+    if (se == NULL) {
+	return(NULL);
+    }
+    if (se->ah == NULL) {
+	se->ah = apply_init(se->fsm);
+    }
+    return(se->ah);
+}
+
+struct fsm *stack_pop(void) {
+  int i;
+  struct fsm *fsm;
+  struct stack_entry *stack_ptr;
+  if (stack_size() == 1) {
+    fsm = main_stack->fsm;
+    main_stack->fsm = NULL;
+    stack_clear();
+    return(fsm);
+  }
+  for (i=0, stack_ptr = main_stack; (stack_ptr->next)->number != -1; stack_ptr = stack_ptr->next, i++);
+  (stack_ptr->previous)->next = stack_ptr->next;
+  (stack_ptr->next)->previous = stack_ptr->previous;
+  fsm = stack_ptr->fsm;
+  if (stack_ptr->ah != NULL) {
+      apply_clear(stack_ptr->ah);
+      stack_ptr->ah = NULL;
+  }
+  if (stack_ptr->amedh != NULL) {
+      apply_med_clear(stack_ptr->amedh);
+      stack_ptr->amedh = NULL;
+  }
+  stack_ptr->fsm = NULL;
+  xxfree(stack_ptr);
+  return(fsm);
+}
+
+int stack_isempty () {
+  if (main_stack->next == NULL) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int stack_turn () {
+  struct stack_entry *stack_ptr;
+  if (stack_isempty()) {
+    printf("Stack is empty.\n");
+    return 0;
+  }
+  if (stack_size() == 1) {
+    return 1;
+  }
+
+  stack_ptr = stack_find_top();
+  main_stack->next = stack_ptr->next;
+  (stack_ptr->next)->previous = main_stack;
+  main_stack = stack_ptr;
+
+  while (stack_ptr->previous != NULL) {
+    stack_ptr->next = stack_ptr->previous;
+    stack_ptr = stack_ptr->next;
+  }
+  for (stack_ptr = main_stack; stack_ptr->number != -1;) {
+    (stack_ptr->next)->previous = stack_ptr;
+  }
+  return 1;
+}
+
+struct stack_entry *stack_find_top () {
+  struct stack_entry *stack_ptr;
+  if (main_stack->number == -1) {
+    return NULL;
+  }
+  for (stack_ptr = main_stack; (stack_ptr->next)->number != -1; stack_ptr = stack_ptr->next);
+  return(stack_ptr);
+}
+
+struct stack_entry *stack_find_bottom () {
+  if (main_stack->number == -1) {
+    return NULL;
+  }
+  return(main_stack);
+}
+
+struct stack_entry *stack_find_second () {
+  struct stack_entry *stack_ptr;
+  /*
+      if (main_stack->number == -1) {
+      return NULL;
+      }
+  */
+  for (stack_ptr = main_stack; (stack_ptr->next)->number != -1; stack_ptr = stack_ptr->next);
+  return(stack_ptr->previous);
+}
+
+int stack_clear(void) {
+  struct stack_entry *stack_ptr;
+  for (stack_ptr = main_stack ; stack_ptr->next != NULL; stack_ptr = main_stack) {
+    if (stack_ptr->ah != NULL)
+	apply_clear(stack_ptr->ah);
+    if (stack_ptr->amedh != NULL)
+	apply_med_clear(stack_ptr->amedh);
+
+    main_stack = stack_ptr->next;
+    fsm_destroy(stack_ptr->fsm);
+    xxfree(stack_ptr);
+  }
+  xxfree(stack_ptr);
+  return(stack_init());
+}
+
+int stack_rotate () {
+
+  /* Top element of stack to bottom */
+  struct stack_entry *stack_ptr;
+  struct fsm *temp_fsm;
+
+  if (stack_isempty()) {
+    printf("Stack is empty.\n");
+    return -1;
+  }
+  if (stack_size() == 1) {
+    return 1;
+  }
+  stack_ptr = stack_find_top();
+  temp_fsm = main_stack->fsm;
+  main_stack->fsm = stack_ptr->fsm;
+  stack_ptr->fsm = temp_fsm;
+  return 1;
+}
+
+int stack_print () {
+  return 1;
+}
diff --git a/back-ends/foma/cpp-version/stringhash.cc b/back-ends/foma/cpp-version/stringhash.cc
new file mode 100644
index 0000000..3e7d008
--- /dev/null
+++ b/back-ends/foma/cpp-version/stringhash.cc
@@ -0,0 +1,101 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include "fomalib.h"
+
+#define STRING_HASH_SIZE 8191
+
+unsigned int sh_hashf(char *string);
+
+struct sh_handle *sh_init() {
+    struct sh_handle *sh;
+    sh = (struct sh_handle*)xxmalloc(sizeof(struct sh_handle));
+    sh->hash = (struct sh_hashtable*)xxcalloc(STRING_HASH_SIZE, sizeof(struct sh_hashtable));
+    return(sh);
+}
+
+void sh_done(struct sh_handle *sh) {
+    int i;
+    struct sh_hashtable *hash, *hashp;
+    for (i=0; i < STRING_HASH_SIZE; i++) {
+	hash = sh->hash + i;
+	if (hash->string != NULL)
+	    xxfree(hash->string);
+	for (hash=hash->next ; hash != NULL ; hash = hashp) {
+	    hashp = hash->next;
+	    if (hash->string != NULL)
+		xxfree(hash->string);
+	    xxfree(hash);
+	}
+    }
+    xxfree(sh->hash);
+    xxfree(sh);
+}
+
+int sh_get_value(struct sh_handle *sh) {
+    return(sh->lastvalue);
+}
+
+char *sh_find_string(struct sh_handle *sh, char *string) {
+    struct sh_hashtable *hash;
+    for (hash = sh->hash + sh_hashf(string) ; hash != NULL; hash = hash->next) {
+	if (hash->string == NULL)
+	    return NULL;
+	if (strcmp(hash->string, string) == 0) {
+	    sh->lastvalue = hash->value;
+	    return(hash->string);
+	}
+    }
+    return NULL;
+}
+
+char *sh_find_add_string(struct sh_handle *sh, char *string, int value) {
+    char *s;
+    s = sh_find_string(sh, string);
+    if (s == NULL)
+	return (sh_add_string(sh, string, value));
+    else
+	return(s);
+}
+
+char *sh_add_string(struct sh_handle *sh, char *string, int value) {
+    struct sh_hashtable *hash, *newhash;
+    
+    hash = sh->hash + sh_hashf(string);
+    if (hash->string == NULL) {
+	hash->string = xxstrdup(string);
+	hash->value = value;
+	return(hash->string);
+    } else {
+        newhash = (struct sh_hashtable*)xxmalloc(sizeof(struct sh_hashtable));
+	newhash->string = xxstrdup(string);
+	newhash->value = value;
+	newhash->next = hash->next;
+	hash->next = newhash;
+	return(newhash->string);
+    }
+}
+
+unsigned int sh_hashf(char *string) {
+    register unsigned int hash;
+    hash = 0;
+    
+    while (*string != '\0') {
+        hash = hash * 101  +  *string++;
+    }
+    return (hash % STRING_HASH_SIZE);
+}
diff --git a/back-ends/foma/cpp-version/structures.cc b/back-ends/foma/cpp-version/structures.cc
new file mode 100644
index 0000000..2a779ab
--- /dev/null
+++ b/back-ends/foma/cpp-version/structures.cc
@@ -0,0 +1,922 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#if defined(ORIGINAL) || ! defined(_MSC_VER)
+  #include <sys/time.h>
+#endif
+#include "foma.h"
+
+static struct defined_quantifiers *quantifiers;
+
+char *fsm_get_library_version_string() {
+    static char s[20];
+    sprintf(s,"%i.%i.%i%s",MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,STATUS_VERSION);
+    return(s);
+}
+
+#ifdef ORIGINAL
+int linesortcompin(struct fsm_state *a, struct fsm_state *b) {
+    return (a->in - b->in);
+}
+
+int linesortcompout(struct fsm_state *a, struct fsm_state *b) {
+    return (a->out - b->out);
+}
+#else
+  int linesortcompin(const void *a, const void *b) {
+      return (((struct fsm_state*)a)->in - ((struct fsm_state*)b)->in);
+    }
+  int linesortcompout(const void *a, const void *b) {
+      return (((struct fsm_state*)a)->out - ((struct fsm_state*)b)->out);
+    }
+#endif
+
+
+void fsm_sort_arcs(struct fsm *net, int direction) {
+    /* direction 1 = in, direction = 2, out */
+    struct fsm_state *fsm;
+    int i, lasthead, numlines;
+#ifdef ORIGINAL
+    int(*scin)() = linesortcompin;
+    int(*scout)() = linesortcompout;
+#else
+    int(*scin)(const void*, const void*) = linesortcompin;
+    int(*scout)(const void*, const void*) = linesortcompout;
+#endif
+    fsm = net->states;
+    for (i=0, numlines = 0, lasthead = 0 ; (fsm+i)->state_no != -1; i++) {
+	if ((fsm+i)->state_no != (fsm+i+1)->state_no || (fsm+i)->target == -1) {
+	    numlines++;
+	    if ((fsm+i)->target == -1) {
+		numlines--;
+	    }
+	    if (numlines > 1) {
+		/* Sort, set numlines = 0 */
+		if (direction == 1)
+		    qsort(fsm+lasthead, numlines, sizeof(struct fsm_state), scin);
+		else
+		    qsort(fsm+lasthead, numlines, sizeof(struct fsm_state), scout);
+	    }
+	    numlines = 0;
+	    lasthead = i + 1;
+	    continue;
+	}
+	numlines++;
+    }
+    if (net->arity == 1) {
+	net->arcs_sorted_in = 1;
+	net->arcs_sorted_out = 1;
+	return;
+    }
+    if (direction == 1) {
+	net->arcs_sorted_in = 1;
+	net->arcs_sorted_out = 0;
+    }
+    if (direction == 2) {
+	net->arcs_sorted_out = 1;
+	net->arcs_sorted_in = 0;
+    }
+}
+
+struct state_array *map_firstlines(struct fsm *net) {
+    struct fsm_state *fsm;
+    struct state_array *sa;
+    int i, sold;
+    sold = -1;
+    sa = (struct state_array *)xxmalloc(sizeof(struct state_array)*((net->statecount)+1));
+    fsm = net->states;
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->state_no != sold) {
+            (sa+((fsm+i)->state_no))->transitions = fsm+i;
+            sold = (fsm+i)->state_no;
+        }
+    }
+    return(sa);
+}
+
+struct fsm *fsm_boolean(int value) {
+    if (value == 0)
+        return (fsm_empty_set());
+    else
+        return(fsm_empty_string());
+}
+
+struct fsm *fsm_sigma_net(struct fsm *net) {
+    /* Extract sigma and create net with one arc            */
+    /* from state 0 to state 1 with each (state 1 is final) */
+    struct sigma *sig;
+    int pathcount;
+
+    if (sigma_size(net->sigma) == 0) {
+	fsm_destroy(net);
+        return(fsm_empty_set());
+    }
+    
+    fsm_state_init(sigma_max(net->sigma));
+    fsm_state_set_current_state(0, 0, 1);
+    pathcount = 0;
+    for (sig = net->sigma; sig != NULL; sig = sig->next) {
+        if (sig->number >=3 || sig->number == IDENTITY) {
+            pathcount++;
+            fsm_state_add_arc(0,sig->number, sig->number, 1, 0, 1);
+        }
+    }
+    fsm_state_end_state();
+    fsm_state_set_current_state(1, 1, 0);
+    fsm_state_end_state();
+    xxfree(net->states);
+    fsm_state_close(net);
+    net->is_minimized = YES;
+    net->is_loop_free = YES;
+    net->pathcount = pathcount;
+    sigma_cleanup(net, 1);
+    return(net);
+}
+
+struct fsm *fsm_sigma_pairs_net(struct fsm *net) {
+    /* Create FSM of attested pairs */
+    struct fsm_state *fsm;
+    char *pairs;
+    short int in, out;
+    int i, pathcount, smax;
+    
+    smax = sigma_max(net->sigma)+1;
+    pairs = (char *)xxcalloc(smax*smax, sizeof(char));
+
+    fsm_state_init(sigma_max(net->sigma));
+    fsm_state_set_current_state(0, 0, 1);
+    pathcount = 0;
+    for (fsm = net->states, i=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target == -1)
+            continue;
+        in = (fsm+i)->in;
+        out = (fsm+i)->out;
+        if (*(pairs+smax*in+out) == 0) {
+            fsm_state_add_arc(0,in,out, 1, 0, 1);
+            *(pairs+smax*in+out) = 1;
+            pathcount++;
+        }
+    }
+    fsm_state_end_state();
+    fsm_state_set_current_state(1, 1, 0);
+    fsm_state_end_state();
+
+    xxfree(pairs);
+    xxfree(net->states);
+
+    fsm_state_close(net);
+    if (pathcount == 0) {
+        fsm_destroy(net);
+        return(fsm_empty_set());
+    }
+    net->is_minimized = YES;
+    net->is_loop_free = YES;
+    net->pathcount = pathcount;
+    sigma_cleanup(net, 1);
+    return(net);
+}
+
+int fsm_sigma_destroy(struct sigma *sigma) {
+    struct sigma *sig, *sigp;
+    for (sig = sigma, sigp = NULL; sig != NULL; sig = sigp) {
+	sigp = sig->next;
+	if (sig->symbol != NULL) {
+	    xxfree(sig->symbol);
+	    sig->symbol = NULL;
+	}
+	xxfree(sig);
+    }
+    return 1;
+}
+
+int fsm_destroy(struct fsm *net) {
+    if (net == NULL) {
+        return 0;
+    }
+    if (net->medlookup != NULL && net->medlookup->confusion_matrix != NULL) {
+        xxfree(net->medlookup->confusion_matrix);
+	net->medlookup->confusion_matrix = NULL;
+    }
+    if (net->medlookup != NULL) {
+        xxfree(net->medlookup);
+	net->medlookup = NULL;
+    }
+    fsm_sigma_destroy(net->sigma);
+    net->sigma = NULL;
+    if (net->states != NULL) {
+        xxfree(net->states);
+	net->states = NULL;
+    }
+    xxfree(net);
+    return(1);
+}
+
+struct fsm *fsm_create (char *name) {
+  struct fsm *fsm;
+  fsm = (struct fsm *)xxmalloc(sizeof(struct fsm));
+  strcpy(fsm->name, name);
+  fsm->arity = 1;
+  fsm->arccount = 0;
+  fsm->is_deterministic = NO;
+  fsm->is_pruned = NO;
+  fsm->is_minimized = NO;
+  fsm->is_epsilon_free = NO;
+  fsm->is_loop_free = NO;
+  fsm->arcs_sorted_in = NO;
+  fsm->arcs_sorted_out = NO;
+  fsm->sigma = sigma_create();
+  fsm->states = NULL;
+  fsm->medlookup = NULL;
+  return(fsm);
+}
+
+struct fsm *fsm_empty_string() {
+  struct fsm *net;
+  net = fsm_create("");
+  net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*2);
+  add_fsm_arc(net->states, 0, 0, -1, -1, -1, 1, 1);
+  add_fsm_arc(net->states, 1, -1, -1, -1, -1, -1, -1);
+  fsm_update_flags(net,YES,YES,YES,YES,YES,NO);
+  net->statecount = 1;
+  net->finalcount = 1;
+  net->arccount = 0;
+  net->linecount = 2;
+  net->pathcount = 1;
+  return(net);
+}
+
+struct fsm *fsm_identity() {
+  struct fsm *net;
+  struct sigma *sigma;
+  net = fsm_create("");
+  xxfree(net->sigma);
+  net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*3);
+  add_fsm_arc(net->states, 0, 0, 2, 2, 1, 0, 1);
+  add_fsm_arc(net->states, 1, 1, -1, -1, -1, 1, 0);
+  add_fsm_arc(net->states, 2, -1, -1, -1, -1, -1, -1);
+  sigma = (struct sigma *)xxmalloc(sizeof(struct sigma));
+  sigma->number = IDENTITY;
+  sigma->symbol = xxstrdup("@_IDENTITY_SYMBOL_@");
+  sigma->next = NULL;
+  net->sigma = sigma;
+  fsm_update_flags(net,YES,YES,YES,YES,YES,NO);
+  net->statecount = 2;
+  net->finalcount = 1;
+  net->arccount = 1;
+  net->linecount = 3;
+  net->pathcount = 1;
+  return(net);
+}
+
+struct fsm *fsm_empty_set() {
+  struct fsm *net;
+  net = fsm_create("");
+  net->states = fsm_empty();
+  fsm_update_flags(net,YES,YES,YES,YES,YES,NO);
+  net->statecount = 1;
+  net->finalcount = 0;
+  net->arccount = 0;
+  net->linecount = 2;
+  net->pathcount = 0;
+  return(net);
+}
+
+struct fsm_state *fsm_empty() {
+  struct fsm_state *new_fsm;
+  new_fsm = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*2);
+  add_fsm_arc(new_fsm, 0, 0, -1, -1, -1, 0, 1);
+  add_fsm_arc(new_fsm, 1, -1, -1, -1, -1, -1, -1);
+  return(new_fsm);
+}
+
+int fsm_isuniversal(struct fsm *net) {
+    struct fsm_state *fsm;
+    net = fsm_minimize(net);
+    fsm_compact(net);
+    fsm = net->states;
+    if ((fsm->target == 0 && fsm->final_state == 1 && (fsm+1)->state_no == 0) &&
+        (fsm->in == IDENTITY && fsm->out == IDENTITY) &&
+        ((fsm+1)->state_no == -1) &&
+        (sigma_max(net->sigma)<3) ) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+int fsm_isempty(struct fsm *net) {
+    struct fsm_state *fsm;
+    net = fsm_minimize(net);
+    fsm = net->states;
+    if (fsm->target == -1 && fsm->final_state == 0 && (fsm+1)->state_no == -1)
+        return 1;
+    else
+        return 0;
+}
+
+int fsm_issequential(struct fsm *net) {
+    int i, *sigtable, sequential, seentrans, epstrans, laststate, insym;
+    struct fsm_state *fsm;
+    sigtable = (int *)xxcalloc(sigma_max(net->sigma)+1,sizeof(int));
+    for (i = 0 ; i < sigma_max(net->sigma)+1; i++) {
+	sigtable[i] = -2;
+    }
+    fsm = net->states;
+    seentrans = epstrans = 0;
+    laststate = -1;
+    for (sequential = 1, i = 0; (fsm+i)->state_no != -1 ; i++) {
+	insym = (fsm+i)->in;
+	if (insym < 0) {
+	    continue;
+	}
+	if ((fsm+i)->state_no != laststate) {
+	    laststate = (fsm+i)->state_no;
+	    epstrans = 0;
+	    seentrans = 0;
+	}
+	if (*(sigtable+insym) == laststate || epstrans == 1) {
+	    sequential = 0;
+	    break;
+	}
+	if (insym == EPSILON) {
+	    if (epstrans == 1 || seentrans == 1) {
+		sequential = 0;
+		break;
+	    }
+	    epstrans = 1;
+	}
+	*(sigtable+insym) = laststate;
+	seentrans = 1;
+    }
+    xxfree(sigtable);
+    if (!sequential)
+	printf("fails at state %i\n",(fsm+i)->state_no);
+    return(sequential);
+}
+
+int fsm_isfunctional(struct fsm *net) {
+    return(fsm_isidentity(fsm_minimize(fsm_compose(fsm_invert(fsm_copy(net)),fsm_copy(net)))));
+}
+
+int fsm_isunambiguous(struct fsm *net) {
+    struct fsm *loweruniqnet, *testnet;
+    int ret;
+    loweruniqnet = fsm_lowerdet(fsm_copy(net));
+    testnet = fsm_minimize(fsm_compose(fsm_invert(fsm_copy(loweruniqnet)),fsm_copy(loweruniqnet)));
+    ret = fsm_isidentity(testnet);
+    fsm_destroy(loweruniqnet);
+    fsm_destroy(testnet);
+    return(ret);
+}
+
+struct fsm *fsm_extract_ambiguous_domain(struct fsm *net) {
+    // define AmbiguousDom(T) [_loweruniq(T) .o. _notid(_loweruniq(T).i .o. _loweruniq(T))].u;
+    struct fsm *loweruniqnet, *result;
+    loweruniqnet = fsm_lowerdet(net);
+    result = fsm_topsort(fsm_minimize(fsm_upper(fsm_compose(fsm_copy(loweruniqnet),fsm_extract_nonidentity(fsm_compose(fsm_invert(fsm_copy(loweruniqnet)), fsm_copy(loweruniqnet)))))));
+    fsm_destroy(loweruniqnet);
+    sigma_cleanup(result,1);
+    fsm_compact(result);
+    sigma_sort(result);
+    return(result);
+}
+
+struct fsm *fsm_extract_ambiguous(struct fsm *net) {
+    struct fsm *result;
+    result = fsm_topsort(fsm_minimize(fsm_compose(fsm_extract_ambiguous_domain(fsm_copy(net)), net)));
+    return(result);
+}
+
+struct fsm *fsm_extract_unambiguous(struct fsm *net) {
+    struct fsm *result;
+    result = fsm_topsort(fsm_minimize(fsm_compose(fsm_complement(fsm_extract_ambiguous_domain(fsm_copy(net))), net)));
+    return(result);
+}
+
+int fsm_isidentity(struct fsm *net) {
+
+    /* We check whether a given transducer only produces identity relations     */
+    /* By doing a DFS on the graph, and storing, for each state a "discrepancy" */
+    /* string, showing the current "debt" on the upper or lower side.           */
+    /* We immediately fail if: */
+    /* a) we encounter an already seen state with a different current           */
+    /*    discrepancy than what is stored in the state.                         */
+    /* b) when traversing an arc, we encounter a mismatch between the arc and   */
+    /*    the current discrepancy.                                              */
+    /* c) we encounter a final state and have a non-null current discrepancy.   */
+    /* d) we encounter @ with a non-null discrepancy anywhere.                  */
+    /* e) we encounter ? anywhere.                                              */
+    
+    struct discrepancy {
+        short int *string;
+        short int length;
+        Boolean visited;
+    };
+
+    struct state_array *state_array;
+    struct fsm_state *curr_ptr;
+    int i, j, v, vp, num_states, factor = 0, newlength = 1, startfrom;
+    short int in, out, *newstring;
+    struct discrepancy *discrepancy, *currd, *targetd;
+
+    fsm_minimize(net);
+    fsm_count(net);
+    
+    num_states = net->statecount;
+    discrepancy = (struct discrepancy *)xxcalloc(num_states,sizeof(struct discrepancy));
+    state_array = map_firstlines(net);
+    ptr_stack_clear();
+    ptr_stack_push(state_array->transitions);
+
+    while(!ptr_stack_isempty()) {
+
+        curr_ptr = (struct fsm_state*)ptr_stack_pop();
+
+    nopop:
+        v = curr_ptr->state_no; /* source state number */
+        vp = curr_ptr->target;  /* target state number */
+        currd = discrepancy+v;
+        if (v != -1)
+            currd->visited = 1;
+        if (v == -1 || vp == -1)
+            continue;
+        in = curr_ptr->in;
+        out = curr_ptr->out;
+
+        targetd = discrepancy+vp;
+        /* Check arc and conditions e) d) b) */
+        /* e) */
+        if (in == UNKNOWN || out == UNKNOWN)
+            goto fail;
+        /* d) */
+        if (in == IDENTITY && currd->length != 0)
+            goto fail;
+        /* b) */
+        if (currd->length != 0) {
+            if (currd->length > 0 && out != EPSILON && out != *(currd->string))
+                goto fail;
+            if (currd->length < 0 && in != EPSILON && in  != *(currd->string))
+                goto fail;
+        }
+        if (currd->length == 0 && in != out && in != EPSILON && out != EPSILON) {
+            goto fail;
+        }
+
+        /* Calculate new discrepancy */
+        if (currd->length != 0) {
+            if (in != EPSILON && out != EPSILON)
+                factor = 0;
+            else if (in == EPSILON)
+                factor = -1;
+            else if (out == EPSILON)
+                factor = 1;
+            
+            newlength = currd->length + factor;
+            startfrom = (abs(newlength) <= abs(currd->length)) ? 1 : 0;
+
+        } else if (currd->length == 0) {
+            if (in != EPSILON && out != EPSILON) {
+                newlength = 0;
+            } else {
+                newlength = (out == EPSILON) ? 1 : -1;
+            }
+            startfrom = 0;
+        }
+
+        newstring = (short *)xxcalloc(abs(newlength),sizeof(int));
+
+        for (i = startfrom, j = 0; i < abs(currd->length); i++, j++) {
+            *(newstring+j) = *((currd->string)+i);
+        }
+        if (newlength != 0) {
+            if (currd->length > 0 && newlength >= currd->length) {
+                *(newstring+j) = in;
+            }
+            if (currd->length < 0 && newlength <= currd->length) {
+                *(newstring+j) = out;
+            }
+            if (currd->length == 0 && newlength < currd->length) {
+                *(newstring+j) = out;
+            }
+            if (currd->length == 0 && newlength > currd->length) {
+                *(newstring+j) = in;
+            }
+        }
+
+        /* Check target conditions a) c) */
+        /* a) */
+        if (((state_array+vp)->transitions)->final_state && newlength != 0)
+            goto fail;
+        if (curr_ptr->state_no == (curr_ptr+1)->state_no) {
+            ptr_stack_push(curr_ptr+1);
+        }
+        if ((discrepancy+vp)->visited) {
+            //xxfree(newstring);
+            if (targetd->length != newlength)
+                goto fail;
+            for (i=0 ; i < abs(newlength); i++) {
+                if (*((targetd->string)+i) != *(newstring+i))
+                    goto fail;
+            }
+        } else {
+            /* Add discrepancy to target state */
+            targetd->length = newlength;
+            targetd->string = newstring;
+            curr_ptr = (state_array+vp)->transitions;
+            goto nopop;
+        }
+    }
+    xxfree(state_array);
+    xxfree(discrepancy);
+    return 1;
+ fail:
+    xxfree(state_array);
+    xxfree(discrepancy);
+    ptr_stack_clear();
+    return 0;
+}
+
+struct fsm *fsm_markallfinal(struct fsm *net) {
+    struct fsm_state *fsm;
+    int i;
+    fsm = net->states;
+    for (i=0; (fsm+i)->state_no != -1; i++) {
+        (fsm+i)->final_state = YES;
+    }
+    return net;
+}
+
+struct fsm *fsm_lowerdet(struct fsm *net) {
+    unsigned int newsym; /* Running number for new syms */
+    struct fsm_state *fsm;
+    char repstr[13];
+    int i,j,maxsigma,maxarc;
+    net = fsm_minimize(net);
+    fsm_count(net);
+    newsym = 8723643;
+    fsm = net->states;
+    maxarc = 0;
+    maxsigma = sigma_max(net->sigma);
+
+    for (i=0, j=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1)
+            j++;
+        if ((fsm+i+1)->state_no != (fsm+i)->state_no) {
+            maxarc = maxarc > j ? maxarc : j;
+            j = 0;
+        }
+    }
+    if (maxarc > (maxsigma-2)) {
+        for (i=maxarc; i > (maxsigma-2); i--) {
+            sprintf(repstr,"%012X",newsym++);
+            sigma_add(repstr, net->sigma);
+        }
+        sigma_sort(net);
+    }
+    for (i=0, j=3; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1) {
+            (fsm+i)->out = j++;
+            (fsm+i)->in = ((fsm+i)->in == IDENTITY) ? UNKNOWN : (fsm+i)->in;
+        }
+        if ((fsm+i+1)->state_no != (fsm+i)->state_no) {
+            j = 3;
+        }
+    }
+    return(net);
+}
+
+struct fsm *fsm_lowerdeteps(struct fsm *net) {
+    unsigned int newsym; /* Running number for new syms */
+    struct fsm_state *fsm;
+    char repstr[13];
+    int i,j,maxsigma,maxarc;
+    net = fsm_minimize(net);
+    fsm_count(net);
+    newsym = 8723643;
+    fsm = net->states;
+    maxarc = 0;
+    maxsigma = sigma_max(net->sigma);
+
+    for (i=0, j=0; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1)
+            j++;
+        if ((fsm+i+1)->state_no != (fsm+i)->state_no) {
+            maxarc = maxarc > j ? maxarc : j;
+            j = 0;
+        }
+    }
+    if (maxarc > (maxsigma-2)) {
+        for (i=maxarc; i > (maxsigma-2); i--) {
+            sprintf(repstr,"%012X",newsym++);
+            sigma_add(repstr, net->sigma);
+        }
+        sigma_sort(net);
+    }
+    for (i=0, j=3; (fsm+i)->state_no != -1; i++) {
+        if ((fsm+i)->target != -1 && (fsm+i)->out != EPSILON) {
+            (fsm+i)->out = j++;
+            (fsm+i)->in = ((fsm+i)->in == IDENTITY) ? UNKNOWN : (fsm+i)->in;
+        }
+        if ((fsm+i+1)->state_no != (fsm+i)->state_no) {
+            j = 3;
+        }
+    }
+    return(net);
+}
+
+struct fsm *fsm_extract_nonidentity(struct fsm *net) {
+
+    /* Same algorithm as for test identity, except we mark the arcs that cause nonidentity */
+    /* Experimental. */
+
+    struct discrepancy {
+        short int *string;
+        short int length;
+        Boolean visited;
+    };
+
+    struct state_array *state_array;
+    struct fsm_state *curr_ptr;
+    struct fsm *net2;
+    int i, j, v, vp, num_states, factor = 0, newlength = 1, startfrom, killnum;
+    short int in, out, *newstring;
+    struct discrepancy *discrepancy, *currd, *targetd;
+
+    fsm_minimize(net);
+    fsm_count(net);
+    killnum = sigma_add("@KILL@", net->sigma);
+    
+    num_states = net->statecount;
+    discrepancy = (struct discrepancy *)xxcalloc(num_states,sizeof(struct discrepancy));
+    state_array = map_firstlines(net);
+    ptr_stack_push(state_array->transitions);
+
+    while(!ptr_stack_isempty()) {
+
+        curr_ptr = (struct fsm_state*)ptr_stack_pop();
+
+    nopop:
+        v = curr_ptr->state_no; /* source state number */
+        vp = curr_ptr->target;  /* target state number */
+        currd = discrepancy+v;
+        if (v != -1)
+            currd->visited = 1;
+        if (v == -1 || vp == -1)
+            continue;
+        in = curr_ptr->in;
+        out = curr_ptr->out;
+
+        targetd = discrepancy+vp;
+        /* Check arc and conditions e) d) b) */
+        /* e) */
+        if (in == UNKNOWN || out == UNKNOWN)
+            goto fail;
+        /* d) */
+        if (in == IDENTITY && currd->length != 0)
+            goto fail;
+        /* b) */
+        if (currd->length != 0) {
+            if (currd->length > 0 && out != EPSILON && out != *(currd->string))
+                goto fail;
+            if (currd->length < 0 && in != EPSILON && in  != *(currd->string))
+                goto fail;
+        }
+        if (currd->length == 0 && in != out && in != EPSILON && out != EPSILON) {
+            goto fail;
+        }
+
+        /* Calculate new discrepancy */
+        if (currd->length != 0) {
+            if (in != EPSILON && out != EPSILON)
+                factor = 0;
+            else if (in == EPSILON)
+                factor = -1;
+            else if (out == EPSILON)
+                factor = 1;
+            
+            newlength = currd->length + factor;
+            startfrom = (abs(newlength) <= abs(currd->length)) ? 1 : 0;
+
+        } else if (currd->length == 0) {
+            if (in != EPSILON && out != EPSILON) {
+                newlength = 0;
+            } else {
+                newlength = (out == EPSILON) ? 1 : -1;
+            }
+            startfrom = 0;
+        }
+
+        newstring = (short *)xxcalloc(abs(newlength),sizeof(int));
+
+        for (i = startfrom, j = 0; i < abs(currd->length); i++, j++) {
+            *(newstring+j) = *((currd->string)+i);
+        }
+        if (newlength != 0) {
+            if (currd->length > 0 && newlength >= currd->length) {
+                *(newstring+j) = in;
+            }
+            if (currd->length < 0 && newlength <= currd->length) {
+                *(newstring+j) = out;
+            }
+            if (currd->length == 0 && newlength < currd->length) {
+                *(newstring+j) = out;
+            }
+            if (currd->length == 0 && newlength > currd->length) {
+                *(newstring+j) = in;
+            }
+
+        }
+
+        /* Check target conditions a) c) */
+        /* a) */
+        if (((state_array+vp)->transitions)->final_state && newlength != 0)
+            goto fail;
+        if (curr_ptr->state_no == (curr_ptr+1)->state_no) {
+            ptr_stack_push(curr_ptr+1);
+        }
+
+        if ((discrepancy+vp)->visited) {
+            //xxfree(newstring);
+            if (targetd->length != newlength)
+                goto fail;
+            for (i=0 ; i < abs(newlength); i++) {
+                if (*((targetd->string)+i) != *(newstring+i))
+                    goto fail;
+            }
+        } else {
+            /* Add discrepancy to target state */
+            targetd->length = newlength;
+            targetd->string = newstring;
+            curr_ptr = (state_array+vp)->transitions;
+            goto nopop;
+        }
+        continue;
+    fail:
+        curr_ptr->out = killnum;
+        if (curr_ptr->state_no == (curr_ptr+1)->state_no) {
+            ptr_stack_push(curr_ptr+1);
+        }
+    }
+    ptr_stack_clear();
+    sigma_sort(net);
+    net2 = fsm_upper(fsm_compose(net,fsm_contains(fsm_symbol("@KILL@"))));
+    sigma_remove("@KILL@",net2->sigma);
+    sigma_sort(net2);
+    xxfree(state_array);
+    xxfree(discrepancy);
+    return(net2);
+}
+
+struct fsm *fsm_copy (struct fsm *net) {
+    struct fsm *net_copy;
+    if (net == NULL)
+        return net;
+
+    net_copy = (struct fsm *)xxmalloc(sizeof(struct fsm));
+    memcpy(net_copy, net, sizeof(struct fsm));
+
+    fsm_count(net);
+    net_copy->sigma = sigma_copy(net->sigma);
+    net_copy->states = fsm_state_copy(net->states, net->linecount);
+    return(net_copy);
+}
+
+struct fsm_state *fsm_state_copy(struct fsm_state *fsm_state, int linecount) {
+  struct fsm_state *new_fsm_state;
+  
+  new_fsm_state = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(linecount));
+  memcpy(new_fsm_state, fsm_state, linecount*sizeof(struct fsm_state));
+  return(new_fsm_state);
+}
+
+/* TODO: separate linecount and arccount */
+int find_arccount(struct fsm_state *fsm) {
+  int i;
+  for (i=0;(fsm+i)->state_no != -1; i++) {
+  }
+  return i;
+}
+
+void clear_quantifiers() {
+    quantifiers = NULL;
+}
+
+int count_quantifiers() {
+    struct defined_quantifiers *q;
+    int i;
+    for (i = 0, q = quantifiers; q != NULL; q = q->next) {
+	i++;
+    }
+    return(i);
+}
+
+void add_quantifier (char *string) {
+    struct defined_quantifiers *q;
+    if (quantifiers == NULL) {
+	q = (struct defined_quantifiers *)xxmalloc(sizeof(struct defined_quantifiers));
+	quantifiers = q;
+    } else {
+	for (q = quantifiers; q->next != NULL; q = q->next) {
+	    
+	}
+	q->next = (struct defined_quantifiers *)xxmalloc(sizeof(struct defined_quantifiers));
+	q = q->next;
+    }
+    q->name = xxstrdup(string);
+    q->next = NULL;
+}
+
+struct fsm *union_quantifiers() {
+/*     We create a FSM that simply accepts the union of all */
+/*     quantifier symbols */
+    
+    struct fsm *net;
+    struct defined_quantifiers *q;
+    int i, syms, s, symlo;
+    
+    net = fsm_create("");
+    fsm_update_flags(net, YES, YES, YES, YES, NO, NO);
+    
+    for (syms = 0, symlo = 0, q = quantifiers; q != NULL; q = q->next) {
+      s = sigma_add(q->name, net->sigma);
+      if (symlo == 0) {
+	symlo = s;
+      }
+      syms++;
+    }
+    net->states = (struct fsm_state *)xxmalloc(sizeof(struct fsm_state)*(syms+1));
+    for (i = 0; i < syms; i++) {
+	add_fsm_arc(net->states, i, 0, symlo+i, symlo+i, 0, 1, 1);
+    }
+    add_fsm_arc(net->states, i, -1, -1, -1, -1 ,-1 ,-1);
+    net->arccount = syms;
+    net->statecount = net->finalcount = 1;
+    net->linecount = syms;
+    return(net);
+}
+
+char *find_quantifier (char *string) {
+    struct defined_quantifiers *q;
+    for (q = quantifiers; q != NULL; q = q->next) {
+	if (strcmp(string,q->name) == 0)
+	    return q->name;
+    }
+    return(NULL);
+}
+
+void purge_quantifier (char *string) {
+    struct defined_quantifiers *q, *q_prev;
+    for (q = quantifiers, q_prev = NULL; q != NULL; q_prev = q, q = q->next) {
+	if (strcmp(string, q->name) == 0) {
+	    if (q_prev != NULL) {
+		q_prev->next = q->next;
+	    } else {
+		quantifiers = q->next;
+	    }
+	}
+    }
+}
+
+struct fsm *fsm_quantifier(char *string) {
+
+    /* \x* x \x* x \x* */
+    return(fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol(string))),fsm_concat(fsm_symbol(string),fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol(string))),fsm_concat(fsm_symbol(string),fsm_kleene_star(fsm_term_negation(fsm_symbol(string))))))));
+
+}
+
+struct fsm *fsm_logical_precedence(char *string1, char *string2) {
+    /* x < y = \y* x \y* [x | y Q* x] ?* */
+    /*          1  2  3        4           5 */
+    
+    return(fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol(string2))),fsm_concat(fsm_symbol(string1),fsm_concat(fsm_kleene_star(fsm_term_negation(fsm_symbol(string2))),fsm_concat(fsm_union(fsm_symbol(string1),fsm_concat(fsm_symbol(string2),fsm_concat(union_quantifiers(),fsm_symbol(string1)))),fsm_universal())))));
+
+/*    1,3   fsm_kleene_star(fsm_term_negation(fsm_symbol(string2))) */
+/*        2 = fsm_symbol(string1) */
+/*        5 = fsm_universal() */
+/* 4 =    fsm_union(fsm_symbol(string1),fsm_concat(fsm_symbol(string2),fsm_concat(union_quantifiers(),fsm_symbol(string1)))) */
+
+}
+
+/** Logical equivalence, i.e. where two variables span the same substring */
+/** x = y = ?* [x y|y x]/Q ?* [x y|y x]/Q ?* */
+struct fsm *fsm_logical_eq(char *string1, char *string2) {
+  return(fsm_concat(fsm_universal(),fsm_concat(fsm_ignore(fsm_union(fsm_concat(fsm_symbol(string1),fsm_symbol(string2)),fsm_concat(fsm_symbol(string2),fsm_symbol(string1))),union_quantifiers(),OP_IGNORE_ALL),fsm_concat(fsm_universal(),fsm_concat(fsm_ignore(fsm_union(fsm_concat(fsm_symbol(string1),fsm_symbol(string2)),fsm_concat(fsm_symbol(string2),fsm_symbol(string1))),union_quantifiers(),OP_IGNORE_ALL),fsm_universal())))));
+}
+
diff --git a/back-ends/foma/cpp-version/topsort.cc b/back-ends/foma/cpp-version/topsort.cc
new file mode 100644
index 0000000..7ad33d5
--- /dev/null
+++ b/back-ends/foma/cpp-version/topsort.cc
@@ -0,0 +1,170 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "foma.h"
+
+struct fsm *fsm_topsort (struct fsm *net) {
+
+    /* We topologically sort the network by looking for a state          */
+    /* with inverse count 0. We then examine all the arcs from that      */
+    /* state, and decrease the target invcounts. If we find a new        */
+    /* state with invcount 0, we push that on the stack to be treated    */
+    /* If the graph is cyclic, one of two things will happen:            */
+
+    /* (1) We fail to find a state with invcount 0 before we've treated  */
+    /*     all states                                                    */
+    /* (2) A state under treatment has an arc to a state already treated */
+    /*     or itself (we mark a state as treated as soon as we start     */
+    /*     working on it).                                               */
+    /* Of course we also count the number of paths in the network.       */
+
+    int i, j, curr_state, *statemap, treatcount, *order, lc, *newnum, newtarget, newstate;
+    unsigned short int *invcount;
+    unsigned char *treated, overflow;
+    long long grand_pathcount, *pathcount;
+    struct fsm_state *fsm, *curr_fsm, *new_fsm;
+
+    fsm_count(net);
+
+    fsm = net->states;
+    
+    statemap = (int*)xxmalloc(sizeof(int)*net->statecount);
+    order = (int*)xxmalloc(sizeof(int)*net->statecount);
+    pathcount = (long long*)xxmalloc(sizeof(long long)*net->statecount);
+    newnum = (int*)xxmalloc(sizeof(int)*net->statecount);
+    invcount = (unsigned short int*)xxmalloc(sizeof(unsigned short int)*net->statecount);
+    treated =  (unsigned char*)xxmalloc(sizeof(unsigned char)*net->statecount);
+   
+    for (i=0; i < net->statecount; i++) {
+	*(statemap+i) = -1;
+	*(invcount+i) = 0;
+	*(treated+i) = 0;
+	*(order+i) = 0;
+	*(pathcount+i) = 0;
+    }
+
+    for (i=0, lc=0; (fsm+i)->state_no != -1; i++) {
+        lc++;
+        if ((fsm+i)->target != -1) {
+            (*(invcount+(fsm+i)->target))++;
+            /* Do a fast check here to see if we have a selfloop */
+            if ((fsm+i)->state_no == (fsm+i)->target) {
+                net->pathcount = PATHCOUNT_CYCLIC;
+                net->is_loop_free = 0;
+                goto cyclic;
+            }
+        }
+	if (*(statemap+(fsm+i)->state_no) == -1) {
+	    *(statemap+(fsm+i)->state_no) = i;
+	}
+    }
+
+    treatcount = net->statecount;
+    int_stack_clear();
+    int_stack_push(0);
+    grand_pathcount = 0;
+    
+    *(pathcount+0) = 1;
+
+    overflow = 0;
+    for (i=0 ; !int_stack_isempty(); i++) {
+        /* Treat a state */
+        curr_state = int_stack_pop();
+        *(treated+curr_state) = 1;
+        *(order+i) = curr_state;
+        *(newnum+curr_state) = i;
+
+        treatcount--;
+        curr_fsm = fsm+*(statemap+curr_state);
+        while (curr_fsm->state_no == curr_state) {
+            if (curr_fsm->target != -1 ) {
+                (*(invcount+(curr_fsm->target)))--;
+                
+                /* Check if we overflow the path counter */
+
+                if (!overflow) {
+                    *(pathcount+(curr_fsm->target)) += *(pathcount+curr_state);
+                    if ((*(pathcount+(curr_fsm->target)) < 0)) {
+                        overflow = 1;
+                    }
+                }
+                
+                /* Case (1) for cyclic */
+                if (*(treated+(curr_fsm)->target) == 1) {
+                    net->pathcount = PATHCOUNT_CYCLIC;
+                    net->is_loop_free = 0;
+                    goto cyclic;
+                }
+                if ( *(invcount+(curr_fsm->target)) == 0) {
+                    int_stack_push(curr_fsm->target);
+                }
+            }
+            curr_fsm++;
+        }
+    }
+
+    /* Case (2) */
+    if (treatcount > 0) {
+        net->pathcount = PATHCOUNT_CYCLIC;
+        net->is_loop_free = 0;
+        goto cyclic;
+    }
+
+    new_fsm = (struct fsm_state*)xxmalloc(sizeof(struct fsm_state) * (lc+1));
+    for (i=0, j=0 ; i < net->statecount; i++) {
+
+        curr_state = *(order+i);
+        curr_fsm = fsm+*(statemap+curr_state);
+        
+        if (curr_fsm->final_state == 1 && !overflow) {
+            grand_pathcount += *(pathcount + curr_state);
+            if (grand_pathcount < 0)
+                overflow = 1;
+        }
+            
+        for (; curr_fsm->state_no == curr_state; curr_fsm++) {
+                        
+            newstate = curr_fsm->state_no  == -1 ? -1 : *(newnum+(curr_fsm->state_no));
+            newtarget = curr_fsm->target == -1 ? -1 : *(newnum+(curr_fsm->target));
+            add_fsm_arc(new_fsm, j, newstate, curr_fsm->in, curr_fsm->out, newtarget, curr_fsm->final_state, curr_fsm->start_state);
+            j++;
+        }
+    }
+    
+    add_fsm_arc(new_fsm, j, -1, -1, -1, -1, -1, -1);
+    net->states = new_fsm;
+    net->pathcount = grand_pathcount;
+    net->is_loop_free = 1;
+    if (overflow == 1) {
+        net->pathcount = PATHCOUNT_OVERFLOW;
+    }
+    xxfree(fsm);
+
+ cyclic:
+
+    xxfree(statemap);
+    xxfree(order);
+    xxfree(pathcount);
+    xxfree(newnum);
+    xxfree(invcount);
+    xxfree(treated);
+    int_stack_clear();
+    return(net);
+}
diff --git a/back-ends/foma/cpp-version/trie.cc b/back-ends/foma/cpp-version/trie.cc
new file mode 100644
index 0000000..cfe7014
--- /dev/null
+++ b/back-ends/foma/cpp-version/trie.cc
@@ -0,0 +1,151 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2010 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation.                            */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include "fomalib.h"
+
+#define THASH_TABLESIZE 1048573
+#define TRIE_STATESIZE 32768
+
+unsigned int trie_hashf(unsigned int source, char *insym, char *outsym);
+
+struct fsm_trie_handle *fsm_trie_init() {
+    struct fsm_trie_handle *th;
+
+    th = (struct fsm_trie_handle*)xxcalloc(1,sizeof(struct fsm_trie_handle));
+    th->trie_hash = (struct trie_hash*)xxcalloc(THASH_TABLESIZE, sizeof(struct trie_hash));
+    th->trie_states = (struct trie_states*)xxcalloc(TRIE_STATESIZE, sizeof(struct trie_states));
+    th->statesize = TRIE_STATESIZE;
+    th->trie_cursor = 0;
+    th->sh_hash = sh_init();
+    return(th);
+}
+
+struct fsm *fsm_trie_done(struct fsm_trie_handle *th) {
+    struct trie_hash *thash, *thashp;
+    struct fsm *newnet;
+    struct fsm_construct_handle *newh;
+    unsigned int i;
+
+    newh = (struct fsm_construct_handle*)fsm_construct_init("name");
+    for (i = 0; i < THASH_TABLESIZE; i++) {
+	thash = (th->trie_hash)+i;
+	for ( ; thash != NULL; thash = thash->next) {
+	    if (thash->insym != NULL) {
+		fsm_construct_add_arc(newh, thash->sourcestate, thash->targetstate, thash->insym, thash->outsym);
+	    } else {
+		break;
+	    }
+	}
+    }
+    for (i = 0; i <= th->used_states; i++) {
+	if ((th->trie_states+i)->is_final == 1) {
+	    fsm_construct_set_final(newh, i);
+	}
+    }
+    fsm_construct_set_initial(newh, 0);
+    newnet = fsm_construct_done(newh);
+    /* Free all mem */
+    for (i=0; i < THASH_TABLESIZE; i++) {
+	for (thash=((th->trie_hash)+i)->next; thash != NULL; thash = thashp) {
+	    thashp = thash->next;
+	    xxfree(thash);
+	}
+    }
+    sh_done(th->sh_hash);
+    xxfree(th->trie_states);
+    xxfree(th->trie_hash);
+    xxfree(th);
+    return(newnet);
+}
+
+void fsm_trie_add_word(struct fsm_trie_handle *th, char *word) {
+    int i, len;
+    char *wcopy;
+    wcopy = xxstrdup(word);
+    len = strlen(wcopy);
+    for (i=0 ; *word != '\0' && i < len; word = word + utf8skip(word)+1, i++) {
+	strncpy(wcopy, word, utf8skip(word)+1);
+	*(wcopy+utf8skip(word)+1) = '\0';
+	fsm_trie_symbol(th, wcopy, wcopy);
+    }
+    xxfree(wcopy);
+    fsm_trie_end_word(th);
+}
+
+void fsm_trie_end_word(struct fsm_trie_handle *th) {
+    (th->trie_states+th->trie_cursor)->is_final = 1;
+    th->trie_cursor = 0;
+}
+
+void fsm_trie_symbol(struct fsm_trie_handle *th, char *insym, char *outsym) {
+    unsigned int h;
+    struct trie_hash *thash, *newthash;
+
+    h = trie_hashf(th->trie_cursor, insym, outsym);
+    if ((th->trie_hash+h)->insym != NULL) {
+	for (thash = th->trie_hash+h; thash != NULL; thash = thash->next) {
+	    if (strcmp(thash->insym, insym) == 0 && strcmp(thash->outsym, outsym) == 0 && thash->sourcestate == th->trie_cursor) {
+		/* Exists, move cursor */
+		th->trie_cursor = thash->targetstate;
+		return;
+	    }
+	}
+    }
+    /* Doesn't exist */
+    
+    /* Insert trans, move counter and cursor */
+    th->used_states++;
+    thash = th->trie_hash+h;
+    if (thash->insym == NULL) {
+	thash->insym = sh_find_add_string(th->sh_hash, insym,1);
+	thash->outsym = sh_find_add_string(th->sh_hash, outsym,1);
+	thash->sourcestate = th->trie_cursor;
+	thash->targetstate = th->used_states;
+    } else {
+        newthash = (struct trie_hash*)xxcalloc(1, sizeof(struct trie_hash));
+	newthash->next = thash->next;
+	newthash->insym = sh_find_add_string(th->sh_hash, insym,1);
+	newthash->outsym = sh_find_add_string(th->sh_hash, outsym,1);
+	newthash->sourcestate = th->trie_cursor;
+	newthash->targetstate = th->used_states;
+	thash->next = newthash;
+    }
+    th->trie_cursor = th->used_states;
+
+    /* Realloc */
+    if (th->used_states >= th->statesize) {
+	th->statesize = next_power_of_two(th->statesize);
+	th->trie_states = (struct trie_states*)xxrealloc(th->trie_states, th->statesize * sizeof(struct trie_states));
+    }
+    (th->trie_states+th->used_states)->is_final = 0;
+}
+
+unsigned int trie_hashf(unsigned int source, char *insym, char *outsym) {
+
+    /* Hash based on insym, outsym, and sourcestate */
+    register unsigned int hash;
+    hash = 0;
+    
+    while (*insym != '\0') {
+        hash = hash * 101  +  *insym++;
+    }
+    while (*outsym != '\0') {
+        hash = hash * 101  +  *outsym++;
+    }
+    hash = hash * 101 + source;
+    return (hash % THASH_TABLESIZE);
+}
diff --git a/back-ends/foma/cpp-version/utf8.cc b/back-ends/foma/cpp-version/utf8.cc
new file mode 100644
index 0000000..f759d5b
--- /dev/null
+++ b/back-ends/foma/cpp-version/utf8.cc
@@ -0,0 +1,272 @@
+/*     Foma: a finite-state toolkit and library.                             */
+/*     Copyright © 2008-2015 Mans Hulden                                     */
+
+/*     This file is part of foma.                                            */
+
+/*     Foma is free software: you can redistribute it and/or modify          */
+/*     it under the terms of the GNU General Public License version 2 as     */
+/*     published by the Free Software Foundation. */
+
+/*     Foma is distributed in the hope that it will be useful,               */
+/*     but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*     GNU General Public License for more details.                          */
+
+/*     You should have received a copy of the GNU General Public License     */
+/*     along with foma.  If not, see <http://www.gnu.org/licenses/>.         */
+
+#include <stdlib.h>
+#include <string.h>
+#include "foma.h"
+
+unsigned char *int2utf8str(int codepoint);
+
+static int hexstrtoint(char *str);
+
+/* Removes trailing character c, as well as spaces and tabs */
+char *remove_trailing(char *s, char c) {
+    int i, len;
+    len = strlen(s)-1;
+    for (i = len; i>=0 ; i--) {
+        if (*(s+i) != c && *(s+i) != ' ' && *(s+i) != '\t') {
+            break;
+        }
+        *(s+i) = '\0';
+    }
+    return(s);
+}
+
+/* Remove trailing space and \t */
+char *trim(char *string) {
+    int i;
+    if (string == NULL)
+        return(string);
+    for (i = strlen(string) - 1; i >=0; i--) {
+        if (*(string+i) != ' ' && *(string+i) != '\t')
+            break;
+        *(string+i) = '\0';
+    }
+    return(string);
+}
+
+/* Reverses string in-place */
+char *xstrrev(char *str) {
+      char *p1, *p2;
+      if (! str || ! *str)
+            return str;
+      for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
+            *p1 ^= *p2;
+            *p2 ^= *p1;
+            *p1 ^= *p2;
+      }
+      return str;
+}
+
+char *escape_string(char *string, char chr) {
+    size_t i,j;
+    char *newstring;
+    for (i=0,j=0; i < strlen(string); i++) {
+        if (string[i] == chr) {
+            j++;
+        }
+    }
+    if (j>0) {
+        newstring = (char *)xxcalloc((strlen(string)+j),sizeof(char));
+        for (i=0,j=0; i<strlen(string); i++, j++) {
+            if (string[i] == chr) {
+                newstring[j++] = '\\';
+                newstring[j] = chr;
+            } else {
+                newstring[j] = string[i];
+            }
+        }
+        return(newstring);
+    } else {
+        return(string);
+    }
+}
+
+/* Substitute first \n for \0 */
+void strip_newline(char *s) {
+    int i, len;
+    len = strlen(s);
+    /* remove the null terminator */
+    for (i = 0; i < len; i++ ) {
+        if (s[i] == '\n' ) {
+            s[i] = '\0';
+            return;
+        }
+    }
+}
+/* Removes initial and final quote, and decodes the string if it contains special chars */
+void dequote_string(char *s) {
+    int len, i, j;
+    len = strlen(s);
+    if (*s == 0x22 && *(s+len-1) == 0x22) {
+        for (i = 1, j = 0; i<len-1; i++, j++) {
+            *(s+j) = *(s+i);
+
+        }
+        *(s+j) = '\0';
+        decode_quoted(s);
+    }
+}
+
+/* Decode quoted strings. This includes: */
+/* Changing \uXXXX sequences to their unicode equivalents */
+
+void decode_quoted(char *s) {
+    int len, i, j, skip;
+    unsigned char *unistr;
+    
+    len = strlen(s);
+    for (i=0, j=0; i < len; ) {
+        if (*(s+i) == 0x5c && len-i > 5 && *(s+i+1) == 0x75 && ishexstr(s+i+2)) {
+            for (unistr=utf8code16tostr(s+i+2); *unistr; j++, unistr++) {
+                *(s+j) = *unistr;
+            }
+            i += 6;
+        } else {
+            for(skip = utf8skip(s+i)+1; skip > 0; skip--) {
+                *(s+j) = *(s+i);
+                i++; j++;
+            }
+        }
+    }
+    *(s+j) = *(s+i);
+}
+
+
+/* Replace equal length substrings in s */
+char *streqrep(char *s, char *oldstring, char *newstring) {
+    char *ptr;
+    int len;
+    len = strlen(oldstring);
+
+    while ((ptr = strstr(s, oldstring)) != NULL) {
+        memcpy(ptr, newstring, len);
+    }
+    return(s);
+}
+
+int ishexstr (char *str) {
+    int i;
+    for (i=0; i<4; i++) {
+	if ((*(str+i) > 0x2f && *(str+i) < 0x3a) || (*(str+i) > 0x40 && *(str+i) < 0x47) || (*(str+i) > 0x60 && *(str+i) < 0x67))
+	    continue;
+	return 0;
+    }
+    return 1;
+}
+int utf8strlen(char *str) {
+    int i,j, len;
+    len = strlen(str);
+    for (i=0, j=0; *(str+i) != '\0' && i < len;j++ ) {
+        i = i + utf8skip(str+i) + 1;
+    }
+    return j;
+}
+
+/* Checks if the next character in the string is a combining character     */
+/* according to Unicode 7.0                                                */
+/* i.e. codepoints 0300-036F  Combining Diacritical Marks                  */
+/*                 1AB0-1ABE  Combining Diacritical Marks Extended         */
+/*                 1DC0-1DFF  Combining Diacritical Marks Supplement       */
+/*                 20D0-20F0  Combining Diacritical Marks for Symbols      */
+/*                 FE20-FE2D  Combining Half Marks                         */
+/* Returns number of bytes of char. representation, or 0 if not combining  */
+
+int utf8iscombining(unsigned char *s) {
+    if (*s == '\0' || *(s+1) == '\0')
+	return 0;
+    if (!(*s == 0xcc || *s == 0xcd || *s == 0xe1 || *s == 0xe2 || *s == 0xef))
+	return 0;
+    /* 0300-036F */
+    if (*s == 0xcc && *(s+1) >= 0x80 && *(s+1) <= 0xbf)
+	return 2;
+    if (*s == 0xcd && *(s+1) >= 0x80 && *(s+1) <= 0xaf)
+	return 2;
+    if (*(s+2) == '\0')
+	return 0;
+    /* 1AB0-1ABE */
+    if (*s == 0xe1 && *(s+1) == 0xaa && *(s+2) >= 0xb0 && *(s+2) <= 0xbe)
+	return 3;
+    /* 1DC0-1DFF */
+    if (*s == 0xe1 && *(s+1) == 0xb7 && *(s+2) >= 0x80 && *(s+2) <= 0xbf)
+	return 3;
+    /* 20D0-20F0 */
+    if (*s == 0xe2 && *(s+1) == 0x83 && *(s+2) >= 0x90 && *(s+2) <= 0xb0)
+	return 3;
+    /* FE20-FE2D */
+    if (*s == 0xef && *(s+1) == 0xb8 && *(s+2) >= 0xa0 && *(s+2) <= 0xad)
+	return 3;
+    return 0;
+}
+
+int utf8skip(char *str) {
+  unsigned char s;
+
+  s = (unsigned char)(unsigned int) (*str);
+  if (s < 0x80)
+    return 0;
+  if ((s & 0xe0) == 0xc0) {
+    return 1;
+  }
+  if ((s & 0xf0) == 0xe0) {
+    return 2;
+  }
+  if ((s & 0xf8) == 0xf0) {
+    return 3;
+  }
+  return -1;
+}
+
+unsigned char *utf8code16tostr(char *str) {
+  int codepoint;
+  codepoint = (hexstrtoint(str) << 8) + hexstrtoint(str+2);
+  return(int2utf8str(codepoint));
+}
+
+unsigned char *int2utf8str(int codepoint) {
+  unsigned char *value;
+  value = (unsigned char *)xxmalloc(sizeof(unsigned char)*5);
+
+  if (codepoint < 0x80) {
+    *(value) = (unsigned char)(codepoint);
+    *(value+1) = 0;
+    return(value);
+  } else if (codepoint < 0x800) {
+    *(value) = (0xc0 | (unsigned char)(codepoint >> 6));
+    *(value+1) = (0x80 | (unsigned char)(codepoint & 0x3f));
+    *(value+2) = 0;
+    return(value);
+  } else if (codepoint < 0x10000) {
+    *(value) = (0xe0 | (unsigned char)(codepoint >> 12));
+    *(value+1) = (0x80 | (unsigned char)((codepoint >> 6) & 0x3f));
+    *(value+2) = (0x80 | (unsigned char)(codepoint & 0x3f));
+    *(value+3) = 0;
+    return(value);
+  } else {
+    return (0);
+  }
+}
+
+int hexstrtoint(char *str) {
+  int hex;
+
+  if (*str > 0x60) {
+    hex = (*str - 0x57) << 4;
+  } else if (*str > 0x40) {
+    hex = (*str - 0x37) << 4;
+  } else {
+    hex = (*str - 0x30) << 4;
+  }
+  if (*(str+1) > 0x60) {
+    hex += (*(str+1) - 0x57);
+  } else if (*(str+1) > 0x40) {
+    hex += (*(str+1) - 0x37);
+  } else {
+    hex += (*(str+1) - 0x30);
+  }
+  return hex;
+}
diff --git a/back-ends/foma/fomalib.h b/back-ends/foma/fomalib.h
index 3a46bd2..cc2a9a7 100644
--- a/back-ends/foma/fomalib.h
+++ b/back-ends/foma/fomalib.h
@@ -303,7 +303,7 @@ FEXPORT struct fsm *flag_eliminate(struct fsm *net, char *name);
 FEXPORT struct fsm *flag_twosided(struct fsm *net);
 
 /* Compile a rewrite rule */
-FEXPORT struct fsm *fsm_rewrite();
+FEXPORT struct fsm *fsm_rewrite(struct rewrite_set *all_rules);
 
 /* Boolean tests */
 FEXPORT int fsm_isempty(struct fsm *net);
diff --git a/back-ends/openfst/src/include/fst/accumulator.h b/back-ends/openfst/src/include/fst/accumulator.h
index 0048bad..a195780 100644
--- a/back-ends/openfst/src/include/fst/accumulator.h
+++ b/back-ends/openfst/src/include/fst/accumulator.h
@@ -24,15 +24,7 @@
 #include <algorithm>
 #include <functional>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <vector>
 using std::vector;
diff --git a/back-ends/openfst/src/include/fst/arc-map.h b/back-ends/openfst/src/include/fst/arc-map.h
index d898bed..2c2553c 100644
--- a/back-ends/openfst/src/include/fst/arc-map.h
+++ b/back-ends/openfst/src/include/fst/arc-map.h
@@ -23,15 +23,7 @@
 #ifndef FST_LIB_ARC_MAP_H__
 #define FST_LIB_ARC_MAP_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <string>
 #include <utility>
diff --git a/back-ends/openfst/src/include/fst/determinize.h b/back-ends/openfst/src/include/fst/determinize.h
index d5bcafe..177f172 100644
--- a/back-ends/openfst/src/include/fst/determinize.h
+++ b/back-ends/openfst/src/include/fst/determinize.h
@@ -25,15 +25,7 @@
 #include <algorithm>
 #include <climits>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <map>
 #include <fst/slist.h>
diff --git a/back-ends/openfst/src/include/fst/encode.h b/back-ends/openfst/src/include/fst/encode.h
index ae65616..54fb7d2 100644
--- a/back-ends/openfst/src/include/fst/encode.h
+++ b/back-ends/openfst/src/include/fst/encode.h
@@ -23,15 +23,7 @@
 
 #include <climits>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <string>
 #include <vector>
diff --git a/back-ends/openfst/src/include/fst/epsnormalize.h b/back-ends/openfst/src/include/fst/epsnormalize.h
index faec821..c74279a 100644
--- a/back-ends/openfst/src/include/fst/epsnormalize.h
+++ b/back-ends/openfst/src/include/fst/epsnormalize.h
@@ -21,15 +21,7 @@
 #ifndef FST_LIB_EPSNORMALIZE_H__
 #define FST_LIB_EPSNORMALIZE_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <fst/slist.h>
 
diff --git a/back-ends/openfst/src/include/fst/equivalent.h b/back-ends/openfst/src/include/fst/equivalent.h
index e565881..8016119 100644
--- a/back-ends/openfst/src/include/fst/equivalent.h
+++ b/back-ends/openfst/src/include/fst/equivalent.h
@@ -24,15 +24,7 @@
 #include <algorithm>
 #include <deque>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <utility>
 using std::pair; using std::make_pair;
diff --git a/back-ends/openfst/src/include/fst/factor-weight.h b/back-ends/openfst/src/include/fst/factor-weight.h
index cde0192..7cda4bc 100644
--- a/back-ends/openfst/src/include/fst/factor-weight.h
+++ b/back-ends/openfst/src/include/fst/factor-weight.h
@@ -23,15 +23,7 @@
 
 #include <algorithm>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <fst/slist.h>
 #include <string>
diff --git a/back-ends/openfst/src/include/fst/label-reachable.h b/back-ends/openfst/src/include/fst/label-reachable.h
index 2d69ec3..6703244 100644
--- a/back-ends/openfst/src/include/fst/label-reachable.h
+++ b/back-ends/openfst/src/include/fst/label-reachable.h
@@ -23,15 +23,7 @@
 #ifndef FST_LIB_LABEL_REACHABLE_H__
 #define FST_LIB_LABEL_REACHABLE_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <vector>
 using std::vector;
diff --git a/back-ends/openfst/src/include/fst/relabel.h b/back-ends/openfst/src/include/fst/relabel.h
index 8fb78ca..2834348 100644
--- a/back-ends/openfst/src/include/fst/relabel.h
+++ b/back-ends/openfst/src/include/fst/relabel.h
@@ -21,15 +21,7 @@
 #ifndef FST_LIB_RELABEL_H__
 #define FST_LIB_RELABEL_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <string>
 #include <utility>
diff --git a/back-ends/openfst/src/include/fst/replace-util.h b/back-ends/openfst/src/include/fst/replace-util.h
index 9a5e52a..2534d0b 100644
--- a/back-ends/openfst/src/include/fst/replace-util.h
+++ b/back-ends/openfst/src/include/fst/replace-util.h
@@ -26,25 +26,8 @@
 #include <vector>
 using std::vector;
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
-
-#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
+#include <fst/unordered_set.h> // Changed HFST
 
 #include <map>
 
diff --git a/back-ends/openfst/src/include/fst/replace.h b/back-ends/openfst/src/include/fst/replace.h
index d82c53a..791a6ff 100644
--- a/back-ends/openfst/src/include/fst/replace.h
+++ b/back-ends/openfst/src/include/fst/replace.h
@@ -22,15 +22,7 @@
 #ifndef FST_LIB_REPLACE_H__
 #define FST_LIB_REPLACE_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <set>
 #include <string>
@@ -1058,7 +1050,7 @@ class ArcIterator< ReplaceFst<A, T> > {
 
     // If state is already cached, use cached arcs array.
     if (fst_.GetImpl()->HasArcs(state_)) {
-      (fst_.GetImpl())->template CacheImpl<A>::InitArcIterator(state_,
+      (fst_.GetImpl())->CacheImpl<A>::InitArcIterator(state_,
                                                                &cache_data_);
       num_arcs_ = cache_data_.narcs;
       arcs_ = cache_data_.arcs;      // 'arcs_' is a ptr to the cached arcs.
diff --git a/back-ends/openfst/src/include/fst/rmepsilon.h b/back-ends/openfst/src/include/fst/rmepsilon.h
index 4f84b27..5ae0121 100644
--- a/back-ends/openfst/src/include/fst/rmepsilon.h
+++ b/back-ends/openfst/src/include/fst/rmepsilon.h
@@ -21,15 +21,7 @@
 #ifndef FST_LIB_RMEPSILON_H__
 #define FST_LIB_RMEPSILON_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <fst/slist.h>
 #include <stack>
diff --git a/back-ends/openfst/src/include/fst/rmfinalepsilon.h b/back-ends/openfst/src/include/fst/rmfinalepsilon.h
index 93e4c60..8f3ef22 100644
--- a/back-ends/openfst/src/include/fst/rmfinalepsilon.h
+++ b/back-ends/openfst/src/include/fst/rmfinalepsilon.h
@@ -21,16 +21,6 @@
 #ifndef FST_LIB_RMFINALEPSILON_H__
 #define FST_LIB_RMFINALEPSILON_H__
 
-/*#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif*/
-
 #include <vector>
 using std::vector;
 
diff --git a/back-ends/openfst/src/include/fst/sparse-tuple-weight.h b/back-ends/openfst/src/include/fst/sparse-tuple-weight.h
index 0b2aaaf..7d0f472 100644
--- a/back-ends/openfst/src/include/fst/sparse-tuple-weight.h
+++ b/back-ends/openfst/src/include/fst/sparse-tuple-weight.h
@@ -34,15 +34,7 @@
 #include<list>
 #include<stack>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include<tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include<unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <fst/weight.h>
 
@@ -141,7 +133,7 @@ class SparseTupleWeight {
   // Assumes H() function exists for the hash of the key value
   size_t Hash() const {
     uint64 h = 0;
-#ifdef USE_TR1_UNORDERED_MAP
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
     std::tr1::hash<K> H;
 #else
     std::hash<K> H;
diff --git a/back-ends/openfst/src/include/fst/state-map.h b/back-ends/openfst/src/include/fst/state-map.h
index 78c3b76..ea42dac 100644
--- a/back-ends/openfst/src/include/fst/state-map.h
+++ b/back-ends/openfst/src/include/fst/state-map.h
@@ -24,15 +24,7 @@
 
 #include <algorithm>
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
+#include <fst/unordered_map.h> // Changed HFST
 
 #include <string>
 #include <utility>
diff --git a/back-ends/openfst/src/include/fst/symbol-table-ops.h b/back-ends/openfst/src/include/fst/symbol-table-ops.h
index 825edb3..39db4f7 100644
--- a/back-ends/openfst/src/include/fst/symbol-table-ops.h
+++ b/back-ends/openfst/src/include/fst/symbol-table-ops.h
@@ -21,16 +21,6 @@
 using std::vector;
 #include <string>
 
-/*#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif*/
-
 #include <fst/fst.h>
 #include <fst/symbol-table.h>
 
diff --git a/back-ends/openfst/src/include/fst/synchronize.h b/back-ends/openfst/src/include/fst/synchronize.h
index bd15bb6..584e873 100644
--- a/back-ends/openfst/src/include/fst/synchronize.h
+++ b/back-ends/openfst/src/include/fst/synchronize.h
@@ -23,27 +23,6 @@
 
 #include <algorithm>
 
-/*#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
-
-#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif*/
-
-
 #include <string>
 #include <utility>
 using std::pair; using std::make_pair;
diff --git a/back-ends/openfst/src/include/fst/test-properties.h b/back-ends/openfst/src/include/fst/test-properties.h
index a6186ee..18a46b6 100644
--- a/back-ends/openfst/src/include/fst/test-properties.h
+++ b/back-ends/openfst/src/include/fst/test-properties.h
@@ -21,15 +21,7 @@
 #ifndef FST_LIB_TEST_PROPERTIES_H__
 #define FST_LIB_TEST_PROPERTIES_H__
 
-#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif
+#include <fst/unordered_set.h> // Changed HFST
 
 #include <fst/dfs-visit.h>
 #include <fst/connect.h>
diff --git a/back-ends/openfst/src/include/fst/unordered_map.h b/back-ends/openfst/src/include/fst/unordered_map.h
new file mode 100644
index 0000000..b0f1321
--- /dev/null
+++ b/back-ends/openfst/src/include/fst/unordered_map.h
@@ -0,0 +1,13 @@
+#ifdef INCLUDE_TR1_UNORDERED_MAP_AND_SET
+#include <tr1/unordered_map>
+#else
+#include <unordered_map>
+#endif
+
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
+using std::tr1::unordered_map;
+using std::tr1::unordered_multimap;
+#else
+using std::unordered_map;
+using std::unordered_multimap;
+#endif
diff --git a/back-ends/openfst/src/include/fst/unordered_set.h b/back-ends/openfst/src/include/fst/unordered_set.h
new file mode 100644
index 0000000..6633308
--- /dev/null
+++ b/back-ends/openfst/src/include/fst/unordered_set.h
@@ -0,0 +1,13 @@
+#ifdef INCLUDE_TR1_UNORDERED_MAP_AND_SET
+#include <tr1/unordered_set>
+#else
+#include <unordered_set>
+#endif
+
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
+using std::tr1::unordered_set;
+using std::tr1::unordered_multiset;
+#else
+using std::unordered_set;
+using std::unordered_multiset;
+#endif
diff --git a/back-ends/openfst/src/include/fst/util.h b/back-ends/openfst/src/include/fst/util.h
index 9ab16cf..711685e 100644
--- a/back-ends/openfst/src/include/fst/util.h
+++ b/back-ends/openfst/src/include/fst/util.h
@@ -21,26 +21,8 @@
 #ifndef FST_LIB_UTIL_H__
 #define FST_LIB_UTIL_H__
 
-#ifdef USE_TR1_UNORDERED_MAP
-#include <tr1/unordered_map>
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
-#else
-#include <unordered_map>
-using std::unordered_map;
-using std::unordered_multimap;
-#endif
-
-#ifdef USE_TR1_UNORDERED_SET
-#include <tr1/unordered_set>
-using std::tr1::unordered_set;
-using std::tr1::unordered_multiset;
-#else
-#include <unordered_set>
-using std::unordered_set;
-using std::unordered_multiset;
-#endif
-
+#include <fst/unordered_map.h> // Changed HFST
+#include <fst/unordered_set.h> // Changed HFST
 
 #include <list>
 #include <map>
diff --git a/back-ends/openfstwin/src/include/fst/sparse-tuple-weight.h b/back-ends/openfstwin/src/include/fst/sparse-tuple-weight.h
index 29f5953..40411f9 100644
--- a/back-ends/openfstwin/src/include/fst/sparse-tuple-weight.h
+++ b/back-ends/openfstwin/src/include/fst/sparse-tuple-weight.h
@@ -33,9 +33,13 @@
 #include<string>
 #include<list>
 #include<stack>
+
 #include<fst/unordered_map.h> //ChangedPD
-using std::tr1::unordered_map;
-using std::tr1::unordered_multimap;
+#ifdef NO_CPLUSPLUS_11
+  using std::tr1::unordered_multimap;
+#else
+  using std::unordered_multimap;
+#endif
 
 #include <fst/weight.h>
 
@@ -140,7 +144,11 @@ class SparseTupleWeight {
   // Assumes H() function exists for the hash of the key value
   size_t Hash() const {
     uint64 h = 0;
+#ifdef NO_CPLUSPLUS_11
     std::tr1::hash<K> H;
+#else
+    std::hash<K> H;
+#endif
     for (SparseTupleWeightIterator<W, K> it(*this); !it.Done(); it.Next()) {
       h = 5 * h + H(it.Value().first);
       h = 13 * h + it.Value().second.Hash();
diff --git a/back-ends/openfstwin/src/include/fst/unordered_map.h b/back-ends/openfstwin/src/include/fst/unordered_map.h
index 57f3010..cd6eff5 100644
--- a/back-ends/openfstwin/src/include/fst/unordered_map.h
+++ b/back-ends/openfstwin/src/include/fst/unordered_map.h
@@ -1,7 +1,13 @@
 #ifdef _MSC_VER //Added  Paul Dixon
-        #include <unordered_map>
-        using std::unordered_map;
+  #include <unordered_map>
+  #ifdef NO_CPLUSPLUS_11
+    // Basically this means that we are using VC 2008...
+    using std::tr1::unordered_map;
+  #else
+    using std::unordered_map;
+  #endif
 #else
-        #include <tr1/unordered_map>
-        using std::tr1::unordered_map;
+  // This shouldn't happen, resort to tr1 anyways...
+  #include <tr1/unordered_map>
+  using std::tr1::unordered_map;
 #endif
diff --git a/back-ends/openfstwin/src/include/fst/unordered_set.h b/back-ends/openfstwin/src/include/fst/unordered_set.h
index 95da81d..0dc1454 100644
--- a/back-ends/openfstwin/src/include/fst/unordered_set.h
+++ b/back-ends/openfstwin/src/include/fst/unordered_set.h
@@ -1,7 +1,13 @@
-#ifdef _MSC_VER //Added Paul Dixon
-        #include <unordered_set>
-        using std::unordered_set;
+#ifdef _MSC_VER //Added  Paul Dixon
+  #include <unordered_set>
+  #ifdef NO_CPLUSPLUS_11
+    // Basically this means that we are using VC 2008...
+    using std::tr1::unordered_set;
+  #else
+    using std::unordered_set;
+  #endif
 #else
-        #include <tr1/unordered_set>
-        using std::tr1::unordered_set;
+  // This shouldn't happen, resort to tr1 anyways...
+  #include <tr1/unordered_set>
+  using std::tr1::unordered_set;
 #endif
diff --git a/configure.ac b/configure.ac
index 5cedc9b..37be8c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,8 +18,8 @@
 # Information on package
 HFST_NAME=hfst
 HFST_MAJOR=3
-HFST_MINOR=12
-HFST_EXTENSION=1
+HFST_MINOR=13
+HFST_EXTENSION=0
 HFST_VERSION=$HFST_MAJOR.$HFST_MINOR.$HFST_EXTENSION
 
 ### When the VERSION is INCREMENTED, REMEMBER to increment the LONGVERSION too.
@@ -27,11 +27,11 @@ HFST_VERSION=$HFST_MAJOR.$HFST_MINOR.$HFST_EXTENSION
 # for package-config pc file
 LIBHFST_NAME=hfst
 LIBHFST_MAJOR=3
-LIBHFST_MINOR=12
-LIBHFST_EXTENSION=2
+LIBHFST_MINOR=13
+LIBHFST_EXTENSION=0
 LIBHFST_VERSION=$LIBHFST_MAJOR.$LIBHFST_MINOR.$LIBHFST_EXTENSION
 
-AC_INIT([hfst], [3.12.2], [hfst-bugs at helsinki.fi], [hfst])
+AC_INIT([hfst], [3.13.0], [hfst-bugs at helsinki.fi], [hfst])
 AC_CONFIG_AUX_DIR([build-aux])
 AM_INIT_AUTOMAKE([-Wall std-options foreign check-news])
 
@@ -43,9 +43,9 @@ AC_CONFIG_SRCDIR([libhfst/src/HfstTransducer.h])
 AC_CONFIG_HEADERS([config.h libhfst/src/hfst.hpp])
 
 AC_SUBST([LIBHFST_MAJOR],     [3])
-AC_SUBST([LIBHFST_MINOR],     [12])
-AC_SUBST([LIBHFST_EXTENSION], [2])
-AC_SUBST([LIBHFST_VERSION],   [3.12.2])
+AC_SUBST([LIBHFST_MINOR],     [13])
+AC_SUBST([LIBHFST_EXTENSION], [0])
+AC_SUBST([LIBHFST_VERSION],   [3.13.0])
 AC_SUBST([LIBHFST_NAME],      [hfst])
 
 # long version = version vector cast in base 10000, for automatic comparisons
@@ -56,7 +56,7 @@ AC_SUBST([LIBHFST_NAME],      [hfst])
 # $LIBHFST_MINOR * 10000 + $LIBHFST_EXTENSION + "L"
 # NB! It turned out to be not portable, and can't be used!
 
-AC_DEFINE([HFST_LONGVERSION], [300120002L],
+AC_DEFINE([HFST_LONGVERSION], [300130000L],
           [Define to hfst version vector as long in base 10000])
 AC_DEFINE([HFST_REVISION], ["$Revision$"],
           [Automatically substitute to configure.ac revision])
@@ -157,6 +157,16 @@ AC_ARG_WITH([readline],
             [with_readline=$withval],
             [with_readline=no])
 AM_CONDITIONAL([WANT_READLINE], [test x$with_readline != xno])
+# make c++11 features optional; this will disable some functions and make compilation slower
+AC_ARG_WITH([c++11],
+            [AS_HELP_STRING([--with-c++11],
+                            [enable c++11 features @<:@default=yes@:>@])],
+            [with_cplusplus_11=$withval],
+            [with_cplusplus_11=yes])
+AS_IF([test "x$with_cplusplus_11" == "xno"], [AC_DEFINE([NO_CPLUSPLUS_11], [1],
+                                              [Define not to have c++11 support])])
+AS_IF([test "x$with_cplusplus_11" == "xno"], [AC_DEFINE([INCLUDE_TR1_UNORDERED_MAP_AND_SET], [1], [Define unordered container header])])
+AS_IF([test "x$with_cplusplus_11" == "xno"], [AC_DEFINE([USE_TR1_UNORDERED_MAP_AND_SET], [1], [Define unordered container namespace])])
 # make it possible to disable loading entries from shared object (openfst back-end feature),
 # since this adds a dependecy on dl library
 AC_ARG_ENABLE([load_so_entries],
@@ -663,12 +673,14 @@ AC_CHECK_HEADERS([limits.h stdlib.h string.h error.h glob.h locale.h langinfo.h]
 
 AC_LANG_PUSH([C++])
 
-# Always use c++11 (flag 'c++0x' is understood also by older compilers)
+# Always use c++11 (flag 'c++0x' is understood also by older compilers) unless --with-c++11=no or --without-c++11 is requested
 # Checks for highest supported C++ standard
 # But, clang++ does not accept invalid OpenFST code, so limit to C++11 for now
+AS_IF([test "x$with_cplusplus_11" != "xno"],[
 AX_CHECK_COMPILE_FLAG([-std=c++11], [CXXFLAGS="$CXXFLAGS -std=c++11"], [
  AS_IF([echo "$CXXFLAGS" | grep '\-std' | grep -E '((gnu\+\+)|(c\+\+))((11)|(0x)|(14)|(1y)|(17)|(1z))' > /dev/null 2> /dev/null], [], [CXXFLAGS="$CXXFLAGS -std=c++0x"])
 ])
+])
 
 AC_CHECK_HEADERS([unordered_map], [], [],
 [#ifdef HAVE_UNORDERED_MAP
@@ -681,10 +693,12 @@ AC_CHECK_HEADERS([unordered_set], [], [],
 #endif
 ])
 
+AS_IF([test "x$with_cplusplus_11" != "xno"],[
 AS_IF([test "x$ac_cv_header_unordered_map" = "xno"],
             [AC_MSG_ERROR(["<unordered_map> not found, it is needed in c++ standard 11 (or higher)"])])
 AS_IF([test "x$ac_cv_header_unordered_set" = "xno"],
             [AC_MSG_ERROR(["<unordered_set> not found, it is needed in c++ standard 11 (or higher)"])])
+])
 
 AC_CHECK_HEADERS([ext/slist])
 
@@ -798,7 +812,6 @@ cat <<EOF
     *                 name: $enable_name
     *                 optimized-lookup: $enable_optimized_lookup
     *                 pmatch: $enable_pmatch
-    *                 tokenize: $enable_tokenize
     *                 proc: $enable_proc
     *                 project: $enable_project
     *                 prune-alphabet: $enable_prune_alphabet
@@ -816,6 +829,7 @@ cat <<EOF
     *                 summarize: $enable_summarize (summarise)
     *                 tail: $enable_tail
     *                 test: $enable_test
+    *                 tokenize: $enable_tokenize (tokenise)
     *                 twolc: $enable_twolc
     *                 twolc-script: $enable_twolc_script
     *                 tagger: $enable_tagger
@@ -836,6 +850,8 @@ AS_IF([test "x$with_unicode_handler" = "xhfst"],
       [AC_MSG_WARN([HFST only supports basic unicode handling with limited case mapping tables etc.; for better support consider using glib or ICU --with-unicode-handler])])
 AS_IF([test "x$with_readline" == "xno"],
       [AC_MSG_WARN([HFST tools will be compiled without readline; editing user input on command line is not supported; for better support consider using --with-readline])])
+AS_IF([test "x$with_cplusplus_11" == "xno"],
+      [AC_MSG_WARN([HFST tools will be compiled without C++11 support; some features will be disabled; for better support consider using --with-c++11])])
 dnl warn about missing "important" tools
 AS_IF([test "x$enable_lexc" == "xno"],
       [AC_MSG_WARN([hfst-lexc is not enabled; enable with --enable-lexc])])
diff --git a/libhfst/src/HfstDataTypes.cc b/libhfst/src/HfstDataTypes.cc
index 901a67a..d4420c4 100644
--- a/libhfst/src/HfstDataTypes.cc
+++ b/libhfst/src/HfstDataTypes.cc
@@ -11,6 +11,7 @@
 #include <limits.h>
 #include <float.h>
 #include <stdexcept>
+#include <cstdio>
 
 namespace hfst
 {
diff --git a/libhfst/src/HfstExceptionDefs.cc b/libhfst/src/HfstExceptionDefs.cc
index ddefee1..2450cca 100644
--- a/libhfst/src/HfstExceptionDefs.cc
+++ b/libhfst/src/HfstExceptionDefs.cc
@@ -95,6 +95,8 @@ HFST_EXCEPTION_CHILD_DEFINITION(ContextTransducersAreNotAutomataException);
 
 HFST_EXCEPTION_CHILD_DEFINITION(TransducersAreNotAutomataException);
 
+HFST_EXCEPTION_CHILD_DEFINITION(TransducerIsNotAutomatonException);
+
 HFST_EXCEPTION_CHILD_DEFINITION(StateIndexOutOfBoundsException);
 
 HFST_EXCEPTION_CHILD_DEFINITION(TransducerHeaderException);
diff --git a/libhfst/src/HfstExceptionDefs.h b/libhfst/src/HfstExceptionDefs.h
index 42e7ab4..091a9d8 100644
--- a/libhfst/src/HfstExceptionDefs.h
+++ b/libhfst/src/HfstExceptionDefs.h
@@ -306,7 +306,6 @@ HFST_EXCEPTION_CHILD_DECLARATION(ContextTransducersAreNotAutomataException);
 
 
 
-
 /** \brief Transducers are not automata.
 
     This exception is thrown by
@@ -317,6 +316,8 @@ HFST_EXCEPTION_CHILD_DECLARATION(ContextTransducersAreNotAutomataException);
 */
 HFST_EXCEPTION_CHILD_DECLARATION(TransducersAreNotAutomataException);
 
+HFST_EXCEPTION_CHILD_DECLARATION(TransducerIsNotAutomatonException);
+
 /** \brief The StateId argument is not valid.
 
     An example:
diff --git a/libhfst/src/HfstFlagDiacritics.cc b/libhfst/src/HfstFlagDiacritics.cc
index d3b7344..6a5efcd 100644
--- a/libhfst/src/HfstFlagDiacritics.cc
+++ b/libhfst/src/HfstFlagDiacritics.cc
@@ -17,6 +17,9 @@ namespace hfst {
   (FdOperator op, FdFeature feat, FdValue val, const std::string& str):
     op(op), feature(feat), value(val), name(str) {}
 
+  // Required for operator[]()
+  FdOperation::FdOperation(void): op(Pop), feature(0), value(0), name("") {}
+
   FdOperator FdOperation::Operator(void) const { return op; }
   FdFeature FdOperation::Feature(void) const { return feature; }
   FdValue FdOperation::Value(void) const { return value; }
diff --git a/libhfst/src/HfstFlagDiacritics.h b/libhfst/src/HfstFlagDiacritics.h
index 09908db..fe31400 100644
--- a/libhfst/src/HfstFlagDiacritics.h
+++ b/libhfst/src/HfstFlagDiacritics.h
@@ -40,6 +40,9 @@ private:
 public:
     HFSTDLL FdOperation
       (FdOperator op, FdFeature feat, FdValue val, const std::string& str);
+
+    // Required for operator[]()
+    HFSTDLL FdOperation(void);
     
     HFSTDLL FdOperator Operator(void) const;
     HFSTDLL FdFeature Feature(void) const;
@@ -116,17 +119,32 @@ public:
                 FdValue next = hfst::size_t_to_ushort(value_map.size()+1);
                 value_map[val] = next;
             }
-      
-            operations.insert
-              (std::pair<T,FdOperation>
-               (symbol,
-                FdOperation(op, feature_map[feat], value_map[val], str)));
-            symbol_map.insert(std::pair<std::string,T>(str, symbol));
+
+            FdOperation operation(op, feature_map[feat], value_map[val], str);
+            operations[symbol] = operation;
+            symbol_map[str] = symbol;
         }
     
     FdFeature num_features() const { return (hfst::FdFeature)feature_map.size(); }
+
     bool is_diacritic(T symbol) const
         { return operations.find(symbol) != operations.end(); }
+
+    std::vector<T> get_symbols_with_feature(const std::string& feature) const
+        {
+            std::vector<T> retval;
+            if (feature_map.count(feature) == 0) {
+                return retval;
+            }
+            FdFeature feature_code = feature_map.at(feature);
+            for (typename std::map<T, FdOperation>::const_iterator it = operations.begin();
+                 it != operations.end(); ++it) {
+                if ((it->second).Feature() == feature_code) {
+                    retval.push_back(it->first);
+                }
+            }
+            return retval;
+        }
       
     const FdOperation* get_operation(T symbol) const
         {
diff --git a/libhfst/src/HfstInputStream.cc b/libhfst/src/HfstInputStream.cc
index b853642..e262f77 100644
--- a/libhfst/src/HfstInputStream.cc
+++ b/libhfst/src/HfstInputStream.cc
@@ -113,7 +113,7 @@ namespace hfst
         assert(false);
         break;
       }
-    HFST_THROW(HfstFatalException); // make compiler happy
+    HFST_THROW_MESSAGE(HfstFatalException, "stream_get(char &) failed"); // make compiler happy
   }
 
   short &HfstInputStream::stream_get(short &i)
@@ -160,7 +160,7 @@ namespace hfst
         assert(false);
         break;
       }
-    HFST_THROW(HfstFatalException); // make compiler happy
+    HFST_THROW_MESSAGE(HfstFatalException, "stream_get(short &) failed"); // make compiler happy
   }
 
   unsigned short &HfstInputStream::stream_get(unsigned short &i)
@@ -211,7 +211,7 @@ namespace hfst
         assert(false);
         break;
       }
-    HFST_THROW(HfstFatalException); // make compiler happy
+    HFST_THROW_MESSAGE(HfstFatalException, "stream_get() failed"); // make compiler happy
   }
 
   void HfstInputStream::stream_unget(char c)
@@ -1090,6 +1090,70 @@ namespace hfst
       }
   }
   
+  HfstInputStream::HfstInputStream(std::istream &is):
+    bytes_to_skip(0), filename(std::string()), has_hfst_header(false),
+    hfst_version_2_weighted_transducer(false)
+  {
+    input_stream = &is;
+    if (stream_eof()) {
+      HFST_THROW(EndOfStreamException);
+    }
+    type = stream_fst_type();
+
+    if ( ! HfstTransducer::is_lean_implementation_type_available(type)) {
+      throw ImplementationTypeNotAvailableException("ImplementationTypeNotAvailableException", __FILE__, __LINE__, type);
+    }
+
+    switch (type)
+      {
+#if HAVE_SFST || HAVE_LEAN_SFST
+      case SFST_TYPE:
+        HFST_THROW_MESSAGE(FunctionNotImplementedException, "Hfst::InputStream(std::istream) of SFST_TYPE");
+        // implementation.sfst = new hfst::implementations::SfstInputStream(is);
+        break;
+#endif
+#if HAVE_OPENFST
+      case TROPICAL_OPENFST_TYPE:
+        implementation.tropical_ofst = new hfst::implementations::TropicalWeightInputStream(is);
+        break;
+#if HAVE_OPENFST_LOG || HAVE_LEAN_OPENFST_LOG
+      case LOG_OPENFST_TYPE:
+        implementation.log_ofst = new hfst::implementations::LogWeightInputStream(is);
+        break;
+#endif
+#endif
+#if HAVE_FOMA
+      case FOMA_TYPE:
+        HFST_THROW_MESSAGE(FunctionNotImplementedException, "Hfst::InputStream(std::istream) of FOMA_TYPE");
+        // implementation.foma = new hfst::implementations::FomaInputStream(is);
+        break;
+#endif
+#if HAVE_XFSM
+      case XFSM_TYPE:
+        HFST_THROW_MESSAGE(FunctionNotImplementedException, "Hfst::InputStream(std::istream) of XFSM_TYPE");
+        // implementation.xfsm = new hfst::implementations::XfsmInputStream(is);
+        break;
+#endif
+#if HAVE_MY_TRANSDUCER_LIBRARY
+      case MY_TRANSDUCER_LIBRARY_TYPE:
+        HFST_THROW_MESSAGE(FunctionNotImplementedException, "Hfst::InputStream(std::istream) of MY_TRANSDUCER_LIBRARY_TYPE");
+        // implementation.my_transducer_library = new hfst::implementations::MyTransducerLibraryInputStream(is);
+        break;
+#endif
+      case HFST_OL_TYPE:
+          implementation.hfst_ol = new hfst::implementations::HfstOlInputStream(is, false);
+        break;
+      case HFST_OLW_TYPE:
+          implementation.hfst_ol = new hfst::implementations::HfstOlInputStream(is, true);
+        break;
+      default:
+        debug_error("#10b");
+
+        HFST_THROW_MESSAGE(NotTransducerStreamException,
+                           "transducer type not recognised");
+      }
+  }
+
   HfstInputStream::~HfstInputStream(void)
   {
     switch (type)
diff --git a/libhfst/src/HfstInputStream.h b/libhfst/src/HfstInputStream.h
index 01c8dab..6d15ad3 100644
--- a/libhfst/src/HfstInputStream.h
+++ b/libhfst/src/HfstInputStream.h
@@ -247,6 +247,16 @@ For documentation on the HFST binary transducer format, see
     */
     HFSTDLL HfstInputStream(const std::string &filename);
 
+    /** \brief Open a stream to istream \a is for reading binary
+        transducers.
+
+        @throws StreamNotReadableException
+        @throws NotTransducerStreamException
+        @throws EndOfStreamException
+        @throws TransducerHeaderException
+    */
+    HFSTDLL HfstInputStream(std::istream &is);
+
     /** \brief Destructor. */
     HFSTDLL ~HfstInputStream(void);
 
diff --git a/libhfst/src/HfstPrintDot.cc b/libhfst/src/HfstPrintDot.cc
index a0803a6..3cbff0f 100644
--- a/libhfst/src/HfstPrintDot.cc
+++ b/libhfst/src/HfstPrintDot.cc
@@ -51,6 +51,30 @@ namespace hfst {
 #endif
 
 void
+trim_to_valid_utf8(char* inp)
+  {
+    size_t len = strlen(inp);
+    for (int i=1;i<4&&(len-i>0);i++)
+      {
+        if (i < 2 && ((inp[len-i] & 0xc0) == 0xc0))
+          {
+            inp[len-i] = '\0';
+            return;
+          }
+        else if (i < 3 && ((inp[len-i] & 0xe0) == 0xe0))
+          {
+            inp[len-i] = '\0';
+            return;
+          }
+        else if (i < 4 && ((inp[len-i] & 0xf0) == 0xf0))
+          {
+            inp[len-i] = '\0';
+            return;
+          }
+      }
+  }
+
+void
 print_dot(FILE* out, HfstTransducer& t)
   {
     //fprintf(out, "// This graph generated with hfst-fst2txt\n");
@@ -232,6 +256,7 @@ print_dot(FILE* out, HfstTransducer& t)
                       } // if old label empty
                   } // if weighted
               } // if id pair
+            trim_to_valid_utf8(l);
             string sl(l);
             replace_all(sl, "\"", "\\\"");
             target_labels[arc->get_target_state()] = sl;
@@ -430,6 +455,7 @@ print_dot(std::ostream & out, HfstTransducer& t)
                       } // if old label empty
                   } // if weighted
               } // if id pair
+            trim_to_valid_utf8(l);
             string sl(l);
             replace_all(sl, "\"", "\\\"");
             target_labels[arc->get_target_state()] = sl;
diff --git a/libhfst/src/HfstTransducer.cc b/libhfst/src/HfstTransducer.cc
index 6eb145e..964fcca 100644
--- a/libhfst/src/HfstTransducer.cc
+++ b/libhfst/src/HfstTransducer.cc
@@ -2342,7 +2342,29 @@ HfstTransducer &HfstTransducer::output_project()
     /* Add here your implementation. */
     false ); }
 
+HfstTransducer &HfstTransducer::negate()
+{ is_trie = false; // This could be done so that is_trie is preserved
 
+  if (! this->is_automaton())
+    {
+      HFST_THROW_MESSAGE(TransducerIsNotAutomatonException,
+			 "HfstTransducer::negate()");
+    }
+  
+  HfstTransducer idstar("@_IDENTITY_SYMBOL_@", this->type);
+  // diacritics will not be harmonized in subtract
+  StringSet flags = idstar.insert_missing_diacritics_to_alphabet_from(*this);
+  for (StringSet::const_iterator it = flags.begin(); it != flags.end(); it++)
+    {
+      HfstTransducer tr(*it, this->type);
+      idstar.disjunct(tr);
+    }
+  idstar.repeat_star();
+  idstar.minimize();
+  idstar.subtract(*this, true);
+  (*this)=idstar;
+  return *this;
+}
 
 // -----------------------------------------------------------------------
 //
@@ -4521,11 +4543,10 @@ HfstTransducer &HfstTransducer::priority_union (const HfstTransducer &another)
     HfstTransducer t1upper(t1);
     t1upper.input_project().optimize();
     
-    HfstTransducer complement = HfstTransducer::identity_pair( this->type );
-    complement.repeat_star().optimize();
-    complement.subtract(t1upper).prune_alphabet(false);
+    HfstTransducer complement(t1upper);
+    complement.negate().prune_alphabet(false);
 
-    complement.compose(t2).optimize();
+    complement.compose(t2, true).optimize();
 
     HfstTransducer retval(t1);
     retval.disjunct(complement).optimize();
@@ -4863,7 +4884,7 @@ HfstTransducer &HfstTransducer::subtract
 #endif
     /* Add here your implementation. */
     const_cast<HfstTransducer&>(another), harmonize); }
-
+  
 
 // -----------------------------------------------------------------------
 //
diff --git a/libhfst/src/HfstTransducer.h b/libhfst/src/HfstTransducer.h
index 9969194..d8b0991 100644
--- a/libhfst/src/HfstTransducer.h
+++ b/libhfst/src/HfstTransducer.h
@@ -1315,6 +1315,12 @@ ccc : ddd
         to <i>osymbol:osymbol</i>. */
     HFSTDLL HfstTransducer &output_project();
 
+    /** \brief Complement the transducer. 
+
+	Equivalent to [?* - A] where A is this transducer with the exception
+	that flag diacritics are treated as ordinary symbols. */
+    HFSTDLL HfstTransducer &negate();
+    
     /** \brief Compose this transducer with \a another. */
     HFSTDLL HfstTransducer &compose(const HfstTransducer &another,
                             bool harmonize=true);
diff --git a/libhfst/src/HfstXeroxRules.cc b/libhfst/src/HfstXeroxRules.cc
index 790ce46..3e26d33 100644
--- a/libhfst/src/HfstXeroxRules.cc
+++ b/libhfst/src/HfstXeroxRules.cc
@@ -94,7 +94,7 @@ namespace hfst
       {
         HfstTokenizer TOK;
         TOK.add_multichar_symbol("@_EPSILON_SYMBOL_@");
-        hfst::ImplementationType type = hfst::ImplementationType::TROPICAL_OPENFST_TYPE;
+        hfst::ImplementationType type = TROPICAL_OPENFST_TYPE;
         HfstTransducerPair contextPair(HfstTransducer("@_EPSILON_SYMBOL_@", TOK, type),
                                        HfstTransducer("@_EPSILON_SYMBOL_@", TOK, type));
         HfstTransducerPairVector epsilonContext;
diff --git a/libhfst/src/Makefile.am b/libhfst/src/Makefile.am
index 1046015..be4783e 100644
--- a/libhfst/src/Makefile.am
+++ b/libhfst/src/Makefile.am
@@ -104,7 +104,7 @@ HFST_HDRS = \
 
 hfstinclude_HEADERS = $(HFST_HDRS)
 
-libhfst_la_LDFLAGS = -no-undefined -version-info 49:0:0
+libhfst_la_LDFLAGS = -no-undefined -version-info 50:0:0
 
 LIBHFST_TSTS=HfstApply HfstInputStream HfstTransducer \
 		HfstOutputStream HfstXeroxRules HfstRules HfstSymbolDefs \
diff --git a/libhfst/src/implementations/ConvertFomaTransducer.cc b/libhfst/src/implementations/ConvertFomaTransducer.cc
index 6a56ffe..267c453 100644
--- a/libhfst/src/implementations/ConvertFomaTransducer.cc
+++ b/libhfst/src/implementations/ConvertFomaTransducer.cc
@@ -106,7 +106,7 @@ namespace hfst { namespace implementations
   {
     const HfstBasicTransducer::HfstAlphabet & alpha
       = hfst_fsm->get_alphabet();
-    for (HfstBasicTransducer::HfstAlphabet::iterator it
+    for (HfstBasicTransducer::HfstAlphabet::const_iterator it
            = alpha.begin();
          it != alpha.end(); it++)
       {
diff --git a/libhfst/src/implementations/ConvertLogWeightTransducer.cc b/libhfst/src/implementations/ConvertLogWeightTransducer.cc
index 527a681..b1b309f 100644
--- a/libhfst/src/implementations/ConvertLogWeightTransducer.cc
+++ b/libhfst/src/implementations/ConvertLogWeightTransducer.cc
@@ -286,7 +286,7 @@ namespace hfst { namespace implementations
       }
     
     // Add also symbols that do not occur in transitions
-    for (HfstBasicTransducer::HfstAlphabet::iterator it
+    for (HfstBasicTransducer::HfstAlphabet::const_iterator it
            = net->alphabet.begin();
          it != net->alphabet.end(); it++) {
         st.AddSymbol(*it);
diff --git a/libhfst/src/implementations/ConvertSfstTransducer.cc b/libhfst/src/implementations/ConvertSfstTransducer.cc
index 9572240..bfe4b58 100644
--- a/libhfst/src/implementations/ConvertSfstTransducer.cc
+++ b/libhfst/src/implementations/ConvertSfstTransducer.cc
@@ -164,7 +164,7 @@ namespace hfst { namespace implementations
     t->alphabet.add_symbol(internal_identity.c_str(), 2);
     
     // Copy the alphabet
-    for (HfstBasicTransducer::HfstAlphabet::iterator it
+    for (HfstBasicTransducer::HfstAlphabet::const_iterator it
            = net->alphabet.begin();
          it != net->alphabet.end(); it++) {
       if (not is_epsilon(*it) && not is_unknown(*it) && not is_identity(*it))
diff --git a/libhfst/src/implementations/ConvertTropicalWeightTransducer.cc b/libhfst/src/implementations/ConvertTropicalWeightTransducer.cc
index c87018a..c808794 100644
--- a/libhfst/src/implementations/ConvertTropicalWeightTransducer.cc
+++ b/libhfst/src/implementations/ConvertTropicalWeightTransducer.cc
@@ -245,7 +245,7 @@ namespace hfst { namespace implementations
     st.AddSymbol(internal_identity, 2);
     
     // Copy the alphabet
-    for (HfstBasicTransducer::HfstAlphabet::iterator it
+    for (HfstBasicTransducer::HfstAlphabet::const_iterator it
            = net->alphabet.begin();
          it != net->alphabet.end(); it++) {
       assert(! it->empty());
diff --git a/libhfst/src/implementations/HfstBasicTransducer.cc b/libhfst/src/implementations/HfstBasicTransducer.cc
index d823b7e..8b27a02 100644
--- a/libhfst/src/implementations/HfstBasicTransducer.cc
+++ b/libhfst/src/implementations/HfstBasicTransducer.cc
@@ -481,6 +481,10 @@
            final_weight_map[s] = weight;
          }
 
+     void HfstBasicTransducer::remove_final_weight(HfstState s) {
+       final_weight_map.erase(s);
+     }
+
          /** @brief Sort the arcs of this transducer according to input and
              output symbols. */
          HfstBasicTransducer & HfstBasicTransducer::sort_arcs(void)
@@ -2658,7 +2662,11 @@
                for (StringSet::iterator sym_it = substitutions_performed_for_symbols.begin();
                     sym_it != substitutions_performed_for_symbols.end(); sym_it++)
                  {
+#ifdef NO_CPLUSPLUS_11
+                   this->harmonize(substitution_map[*sym_it]);
+#else					 
                    this->harmonize(substitution_map.at(*sym_it));
+#endif			   
                  }
              }
 
diff --git a/libhfst/src/implementations/HfstBasicTransducer.h b/libhfst/src/implementations/HfstBasicTransducer.h
index 2fd90e7..ecfe01a 100644
--- a/libhfst/src/implementations/HfstBasicTransducer.h
+++ b/libhfst/src/implementations/HfstBasicTransducer.h
@@ -348,6 +348,9 @@
          If the state does not exist, it is created. */
      HFSTDLL void set_final_weight(HfstState s,
                                    const HfstTropicalTransducerTransitionData::WeightType & weight);
+
+     /** @brief Remove final weight from state \a s, i.e. make it a non-final state. */
+     HFSTDLL void remove_final_weight(HfstState s);
      
      /** @brief Sort the arcs of this transducer according to input and
          output symbols. */
diff --git a/libhfst/src/implementations/HfstOlTransducer.cc b/libhfst/src/implementations/HfstOlTransducer.cc
index 4c3cda2..3b04781 100644
--- a/libhfst/src/implementations/HfstOlTransducer.cc
+++ b/libhfst/src/implementations/HfstOlTransducer.cc
@@ -22,7 +22,12 @@ namespace hfst { namespace implementations
     i_stream(filename.c_str(), std::ios::in | std::ios::binary),
     input_stream(i_stream),weighted(weighted)
   {}
-  
+
+  HfstOlInputStream::HfstOlInputStream
+  (std::istream &is, bool weighted):
+    input_stream(is),weighted(weighted)
+  {}
+
   /* Skip the identifier string "HFST_OL_TYPE" or "HFST_OLW_TYPE" */
   void HfstOlInputStream::skip_identifier_version_3_0(void)
   { input_stream.ignore((weighted?14:13)); }
diff --git a/libhfst/src/implementations/HfstOlTransducer.h b/libhfst/src/implementations/HfstOlTransducer.h
index 9c66441..d15ad3a 100644
--- a/libhfst/src/implementations/HfstOlTransducer.h
+++ b/libhfst/src/implementations/HfstOlTransducer.h
@@ -42,6 +42,7 @@ namespace hfst { namespace implementations
   public:
     HfstOlInputStream(bool weighted);
     HfstOlInputStream(const std::string &filename, bool weighted);
+    HfstOlInputStream(std::istream &is, bool weighted);
     void open(void);
     void close(void);
     bool is_open(void) const;
diff --git a/libhfst/src/implementations/LogWeightTransducer.cc b/libhfst/src/implementations/LogWeightTransducer.cc
index 87113e3..ff718c7 100644
--- a/libhfst/src/implementations/LogWeightTransducer.cc
+++ b/libhfst/src/implementations/LogWeightTransducer.cc
@@ -35,6 +35,10 @@ namespace hfst { namespace implementations
     input_stream(i_stream)
   {}
 
+  LogWeightInputStream::LogWeightInputStream(std::istream &is):
+    input_stream(is)
+  {}
+
   char LogWeightInputStream::stream_get() {
     return (char) input_stream.get(); }
 
diff --git a/libhfst/src/implementations/LogWeightTransducer.h b/libhfst/src/implementations/LogWeightTransducer.h
index 2d0653a..aa694a8 100644
--- a/libhfst/src/implementations/LogWeightTransducer.h
+++ b/libhfst/src/implementations/LogWeightTransducer.h
@@ -50,6 +50,7 @@ namespace fst
 }
 #endif
 
+#include <stdint.h>
 #ifdef _MSC_VER
 typedef __int64 int64;
 #else
@@ -89,6 +90,7 @@ namespace implementations
   public:
     LogWeightInputStream(void);
     LogWeightInputStream(const std::string &filename);
+    LogWeightInputStream(std::istream &is);
     void close(void);
     bool is_eof(void) const;
     bool is_bad(void) const;
diff --git a/libhfst/src/implementations/Makefile.am b/libhfst/src/implementations/Makefile.am
index fd2e87c..8f661fe 100644
--- a/libhfst/src/implementations/Makefile.am
+++ b/libhfst/src/implementations/Makefile.am
@@ -25,7 +25,7 @@ IMPLEMENTATION_SRCS=ConvertTransducerFormat.cc \
                     compose_intersect/ComposeIntersectFst.cc \
                     compose_intersect/ComposeIntersectUtilities.cc
 
-AM_CXXFLAGS=-Wno-deprecated -g -std=c++0x
+AM_CXXFLAGS=-Wno-deprecated -g
 
 AM_CPPFLAGS = -I${top_srcdir}/libhfst/src -I${top_srcdir}/back-ends/foma \
 		-I${top_srcdir}/back-ends
@@ -79,6 +79,7 @@ if WANT_HFSTOL
 HFST_OL_SRCS=\
 optimized-lookup/transducer.cc optimized-lookup/convert.cc \
 	optimized-lookup/ospell.cc optimized-lookup/pmatch.cc \
+	optimized-lookup/pmatch_tokenize.cc \
 	optimized-lookup/find_epsilon_loops.cc
 endif
 
@@ -123,7 +124,8 @@ hfstolincludedir = $(implincludedir)/optimized-lookup
 hfstolinclude_HEADERS = \
 		optimized-lookup/transducer.h \
 		optimized-lookup/convert.h \
-		optimized-lookup/pmatch.h
+		optimized-lookup/pmatch.h \
+		optimized-lookup/pmatch_tokenize.h
 endif
 
 if WANT_FOMA
diff --git a/libhfst/src/implementations/TropicalWeightTransducer.cc b/libhfst/src/implementations/TropicalWeightTransducer.cc
index 6c9f759..bf26940 100644
--- a/libhfst/src/implementations/TropicalWeightTransducer.cc
+++ b/libhfst/src/implementations/TropicalWeightTransducer.cc
@@ -19,6 +19,10 @@
 #include "back-ends/openfst/src/include/fst/fstlib.h"
 #endif // _MSC_VER
 
+#if defined(USE_FOMA_EPSILON_REMOVAL) && defined(HAVE_FOMA)
+#include "FomaTransducer.h"
+#endif
+
 #ifdef PROFILE_OPENFST
 #include <ctime>
 #endif
@@ -166,7 +170,25 @@ namespace hfst {
 
       CHECK_EPSILON_CYCLES(t, "minimize");
 
+#if defined(USE_FOMA_EPSILON_REMOVAL) && defined(HAVE_FOMA)
+      if (!has_weights(t))
+      	{
+	  hfst::implementations::HfstBasicTransducer * basic1
+	    = hfst::implementations::ConversionFunctions::tropical_ofst_to_hfst_basic_transducer(t);
+	  struct fsm * fst1 = hfst::implementations::ConversionFunctions::hfst_basic_transducer_to_foma(basic1);
+	  struct fsm * fst2 = hfst::implementations::FomaTransducer::remove_epsilons(fst1);
+	  hfst::implementations::HfstBasicTransducer * basic2
+	    = hfst::implementations::ConversionFunctions::foma_to_hfst_basic_transducer(fst2);
+	  delete t;
+	  t = hfst::implementations::ConversionFunctions::hfst_basic_transducer_to_tropical_ofst(basic2);
+	}
+      else
+	{
+	  RmEpsilon<StdArc>(t);
+	}
+#else
       RmEpsilon<StdArc>(t);
+#endif
 
       float w = get_smallest_weight(t);
       if (w < 0)
@@ -184,9 +206,9 @@ namespace hfst {
       Decode(det, encode_mapper);
 
       if (w < 0)
-        {
-          add_to_weights(det, w);
-        }
+	{
+	  add_to_weights(det, w);
+	}
 
       return det;
     }
@@ -211,6 +233,10 @@ namespace hfst {
       input_stream(i_stream)
   {}
 
+  TropicalWeightInputStream::TropicalWeightInputStream(std::istream &is):
+    input_stream(is)
+  {}
+
   char TropicalWeightInputStream::stream_get() {
     return (char) input_stream.get(); }
 
diff --git a/libhfst/src/implementations/TropicalWeightTransducer.h b/libhfst/src/implementations/TropicalWeightTransducer.h
index 48cdf20..1515ec4 100644
--- a/libhfst/src/implementations/TropicalWeightTransducer.h
+++ b/libhfst/src/implementations/TropicalWeightTransducer.h
@@ -51,6 +51,7 @@ namespace fst
 }
 #endif
 
+#include <stdint.h>
 #ifdef _MSC_VER
 typedef __int64 int64;
 #else
@@ -89,6 +90,7 @@ namespace implementations
   public:
     TropicalWeightInputStream(void);
     TropicalWeightInputStream(const std::string &filename);
+    TropicalWeightInputStream(std::istream &is);
     void close(void);
     bool is_eof(void) const;
     bool is_bad(void) const;
diff --git a/libhfst/src/implementations/XfsmTransducer.cc b/libhfst/src/implementations/XfsmTransducer.cc
index 9875852..0739e9e 100644
--- a/libhfst/src/implementations/XfsmTransducer.cc
+++ b/libhfst/src/implementations/XfsmTransducer.cc
@@ -56,7 +56,7 @@ namespace hfst { namespace implementations {
           { HFST_THROW(StreamNotReadableException); }
         list_size = NV_len(net_list);
         if (list_size <= 0)
-          { HFST_THROW(HfstFatalException); }
+          { HFST_THROW_MESSAGE(HfstFatalException, "XfstInputStream::XfsmInputStream(const std::string &)"); }
         list_pos = 0;
       }
     }
@@ -339,7 +339,7 @@ namespace hfst { namespace implementations {
         }
       if (minimize_net(t) == 1)
         {
-          HFST_THROW(HfstFatalException);
+          HFST_THROW_MESSAGE(HfstFatalException, "XfsmTransducer::minimize");
         }
       return t;
     }
@@ -514,14 +514,14 @@ namespace hfst { namespace implementations {
 
     void XfsmTransducer::write_in_att_format(NETptr t, const char * filename)
     {
-      HFST_THROW(HfstFatalException);
+      HFST_THROW_MESSAGE(HfstFatalException, "XfsmTransducer::write_in_att_format");
     }
 
     void XfsmTransducer::write_in_prolog_format(NETptr t, const char * filename)
     {
       char * f = strdup(filename);
       if (write_prolog(t, f) != 0)
-        HFST_THROW(HfstFatalException);
+        HFST_THROW_MESSAGE(HfstFatalException, "XfsmTransducer::write_in_prolog_format");
       free(f);
     }
 
@@ -530,7 +530,7 @@ namespace hfst { namespace implementations {
       char * f = strdup(filename);
       NETptr retval = read_prolog(f);
       if (retval == NULL)
-        HFST_THROW(HfstFatalException);
+        HFST_THROW_MESSAGE(HfstFatalException, "XfsmTransducer::prolog_file_to_xfsm_transducer");
       free(f);
       return retval;
     }
diff --git a/libhfst/src/implementations/optimized-lookup/convert.cc b/libhfst/src/implementations/optimized-lookup/convert.cc
index d50437b..3f76d3f 100644
--- a/libhfst/src/implementations/optimized-lookup/convert.cc
+++ b/libhfst/src/implementations/optimized-lookup/convert.cc
@@ -608,7 +608,7 @@ TransitionTableIndex ConvertFstState::append_transitions(
     ++place;
   }
   
-  for(ConvertTransitionSet::iterator it=transitions.begin();
+  for(ConvertTransitionSet::const_iterator it=transitions.begin();
       it!=transitions.end(); ++it)
   {
     transition_table.append((*it)->to_transition<T>());
diff --git a/libhfst/src/implementations/optimized-lookup/convert.h b/libhfst/src/implementations/optimized-lookup/convert.h
index c5309a0..e45eaae 100644
--- a/libhfst/src/implementations/optimized-lookup/convert.h
+++ b/libhfst/src/implementations/optimized-lookup/convert.h
@@ -161,7 +161,7 @@ struct StatePlaceholder {
         if (input_present(0)) { // if there are epsilons
             offset = hfst::size_t_to_uint(get_transition_placeholders(0).size());
         }
-        for(std::set<SymbolNumber>::iterator flag_it = flag_symbols.begin();
+        for(std::set<SymbolNumber>::const_iterator flag_it = flag_symbols.begin();
             flag_it != flag_symbols.end(); ++flag_it) {
             if (input_present(*flag_it)) {
                 if (symbol == *flag_it) {
diff --git a/libhfst/src/implementations/optimized-lookup/pmatch.cc b/libhfst/src/implementations/optimized-lookup/pmatch.cc
index 8d65f25..bded5f1 100644
--- a/libhfst/src/implementations/optimized-lookup/pmatch.cc
+++ b/libhfst/src/implementations/optimized-lookup/pmatch.cc
@@ -16,20 +16,43 @@ namespace hfst_ol {
 PmatchAlphabet::PmatchAlphabet(std::istream & inputstream,
                                SymbolNumber symbol_count,
                                PmatchContainer * cont):
-    TransducerAlphabet(inputstream, symbol_count, false),
+    TransducerAlphabet(inputstream, symbol_count, true),
     special_symbols(SPECIALSYMBOL_NR_ITEMS, NO_SYMBOL_NUMBER), // SpecialSymbols enum
     container(cont)
 {
     symbol2lists = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
     list2symbols = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
+    capture2captured = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
+    captured2capture = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
     rtns = RtnVector(orig_symbol_count, NULL);
     // We initialize the vector of which symbols have a printable representation
     // with false, then flip those that actually do to true
     printable_vector = std::vector<bool>(orig_symbol_count, false);
+    global_flags = std::vector<bool>(orig_symbol_count, false);
     for (SymbolNumber i = 1; i < symbol_table.size(); ++i) {
-        add_special_symbol(symbol_table[i], i);
-        if (is_flag_diacritic(i)) {
-            printable_vector[i] = false;
+        if (is_special(symbol_table[i])) {
+            add_special_symbol(symbol_table[i], i);
+        } else {
+            if (!is_flag_diacritic(i)) {
+                printable_vector[i] = true;
+            } else {
+                if (is_global_flag(symbol_table[i])) {
+                    global_flags[i] = true;
+                    std::string s = symbol_table[i];
+                    // redefine it as a non-global flag, removing the PMATCH_GLOBAL_ part
+                    std::string feature =  hfst::FdOperation::get_feature(symbol_table[i])
+                        .substr(14, std::string::npos);
+                    std::string value = hfst::FdOperation::get_value(symbol_table[i]);
+                    std::string new_diacritic = s.substr(0, 3) + feature + (value == "" ? "" : "." + value) + "@";
+                    fd_table.define_diacritic(i, new_diacritic);
+                    // finally go over all other known flag diacritics with the non-globalized feature and
+                    // mark them global too
+                    SymbolNumberVector globals = fd_table.get_symbols_with_feature(feature);
+                    for (SymbolNumberVector::iterator it = globals.begin(); it != globals.end(); ++it) {
+                        global_flags[*it] = true;
+                    }
+                }
+            }
         }
     }
 }
@@ -41,14 +64,19 @@ PmatchAlphabet::PmatchAlphabet(TransducerAlphabet const & a,
     container(cont) {
     symbol2lists = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
     list2symbols = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
+    capture2captured = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
+    captured2capture = SymbolNumberVector(orig_symbol_count, NO_SYMBOL_NUMBER);
     rtns = RtnVector(orig_symbol_count, NULL);
     // We initialize the vector of which symbols have a printable representation
     // with false, then flip those that actually do to true
     printable_vector = std::vector<bool>(orig_symbol_count, false);
     for (SymbolNumber i = 1; i < symbol_table.size(); ++i) {
-        add_special_symbol(symbol_table[i], i);
-        if (is_flag_diacritic(i)) {
-            printable_vector[i] = false;
+        if (is_special(symbol_table[i])) {
+            add_special_symbol(symbol_table[i], i);
+        } else {
+            if (!is_flag_diacritic(i)) {
+                printable_vector[i] = true;
+            }
         }
     }
 }
@@ -61,6 +89,8 @@ void PmatchAlphabet::add_symbol(const std::string & symbol)
 {
     symbol2lists.push_back(NO_SYMBOL_NUMBER);
     list2symbols.push_back(NO_SYMBOL_NUMBER);
+    capture2captured.push_back(NO_SYMBOL_NUMBER);
+    captured2capture.push_back(NO_SYMBOL_NUMBER);
     rtns.push_back(NULL);
     printable_vector.push_back(true);
     if (exclusionary_lists.size() != 0) {
@@ -68,14 +98,14 @@ void PmatchAlphabet::add_symbol(const std::string & symbol)
         symbol2lists[symbol_table.size()] = hfst::size_t_to_ushort(symbol_lists.size());
         symbol_lists.push_back(SymbolNumberVector(exclusionary_lists.begin(),
                                                   exclusionary_lists.end()));
-#ifndef _MSC_VER
-        for(const auto & exc: exclusionary_lists) {
-          symbol_list_members[list2symbols[exc]].push_back(symbol_table.size());
-        }
-#else
+#if defined(_MSC_VER) || defined(NO_CPLUSPLUS_11)
         for (SymbolNumberVector::const_iterator exc = exclusionary_lists.begin(); exc != exclusionary_lists.end(); exc++) {
           symbol_list_members[list2symbols[*exc]].push_back(hfst::size_t_to_uint(symbol_table.size()));
         }
+#else
+	for(const auto & exc: exclusionary_lists) {
+          symbol_list_members[list2symbols[exc]].push_back(symbol_table.size());
+        }
 #endif
     }
     TransducerAlphabet::add_symbol(symbol);
@@ -120,11 +150,24 @@ void PmatchAlphabet::add_special_symbol(const std::string & str,
         end_tag_map[symbol_number] = str.substr(
             sizeof("@PMATCH_ENDTAG_") - 1,
             str.size() - (sizeof("@PMATCH_ENDTAG_@") - 1));
-    } else if (is_like_arc(str)) {
-        // Fetch the part between @PMATCH_LIKE_ and @
-        words_like_map[symbol_number] = str.substr(
-            sizeof("@PMATCH_LIKE_") - 1,
-            str.size() - (sizeof("@PMATCH_LIKE_@") - 1));
+    } else if (is_capture_tag(str)) {
+        std::string name_of_capture =
+            str.substr(sizeof("@PMATCH_CAPTURE_") - 1,
+                       str.size() - (sizeof("@PMATCH_CAPTURE_@") - 1));
+        capture_tag_map[name_of_capture] = symbol_number;
+        if (captured_tag_map.count(name_of_capture) != 0) {
+            capture2captured[symbol_number] = captured_tag_map[name_of_capture];
+            captured2capture[captured_tag_map[name_of_capture]] = symbol_number;
+        }
+    } else if (is_captured_tag(str)) {
+        std::string name_of_captured =
+            str.substr(sizeof("@PMATCH_CAPTURED_") - 1,
+                       str.size() - (sizeof("@PMATCH_CAPTURED_@") - 1));
+        captured_tag_map[name_of_captured] = symbol_number;
+        if (capture_tag_map.count(name_of_captured) != 0) {
+            captured2capture[symbol_number] = capture_tag_map[name_of_captured];
+            capture2captured[capture_tag_map[name_of_captured]] = symbol_number;
+        }
     } else if (is_insertion(str)) {
         rtn_names[name_from_insertion(str)] = symbol_number;
     } else if (is_guard(str)) {
@@ -134,8 +177,9 @@ void PmatchAlphabet::add_special_symbol(const std::string & str,
     } else if (is_counter(str)) {
         process_counter(str, symbol_number);
     } else {
-        // it's a regular symbol
         printable_vector[symbol_number] = true;
+        // it's a regular symbol, we shouldn't be here!
+//        std::cerr << "pmatch: warning: symbol " << str << " was wrongly given as a special symbol\n";
     }
 }
 
@@ -300,7 +344,8 @@ PmatchContainer::PmatchContainer(std::istream & inputstream):
     locate_mode(false),
     line_number(0),
     profile_mode(false),
-    single_codepoint_tokenization(false)
+    single_codepoint_tokenization(false),
+    running_weight(0.0)
 {
     set_properties();
     reset_recursion();
@@ -323,15 +368,18 @@ PmatchContainer::PmatchContainer(std::istream & inputstream):
         }
     }
     set_properties(properties);
+    hfst::set_xerox_composition(xerox_composition);
     TransducerHeader header(inputstream);
     alphabet = PmatchAlphabet(inputstream, header.symbol_count(), this);
     orig_symbol_count = symbol_count = alphabet.get_orig_symbol_count();
+    global_flag_state = alphabet.get_fd_table();
     encoder = new Encoder(alphabet.get_symbol_table(), orig_symbol_count);
     toplevel = new hfst_ol::PmatchTransducer(
         inputstream,
         header.index_table_size(),
         header.target_table_size(),
         alphabet,
+        "TOP",
         this);
     while (inputstream.good()) {
         try {
@@ -348,6 +396,7 @@ PmatchContainer::PmatchContainer(std::istream & inputstream):
                                           header.index_table_size(),
                                           header.target_table_size(),
                                           alphabet,
+                                          transducer_name,
                                           this);
         if (!alphabet.has_rtn(transducer_name)) {
             alphabet.add_rtn(rtn, transducer_name);
@@ -363,13 +412,15 @@ PmatchContainer::PmatchContainer(Transducer * t):
     verbose(false),
     locate_mode(false),
     profile_mode(false),
-    single_codepoint_tokenization(false)
+    single_codepoint_tokenization(false),
+    running_weight(0.0)
 {
     set_properties();
     reset_recursion();
     //TransducerHeader header = t->get_header();
     alphabet = PmatchAlphabet(t->get_alphabet(), this);
     orig_symbol_count = symbol_count = alphabet.get_orig_symbol_count();
+    global_flag_state = alphabet.get_fd_table();
     line_number = 0;
     encoder = new Encoder(alphabet.get_symbol_table(), orig_symbol_count);
     TransducerTable<TransitionW> transitions = t->copy_transitionw_table();
@@ -378,6 +429,7 @@ PmatchContainer::PmatchContainer(Transducer * t):
         transitions.get_vector(),
         indices.get_vector(),
         alphabet,
+        "TOP",
         this);
     collect_first_symbols();
 }
@@ -392,7 +444,8 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
     locate_mode(false),
     line_number(0),
     profile_mode(false),
-    single_codepoint_tokenization(false)
+    single_codepoint_tokenization(false),
+    running_weight(0.0)
 {
     set_properties();
     reset_recursion();
@@ -414,6 +467,7 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
         TransducerHeader header(backend->get_header());
         alphabet = PmatchAlphabet(backend->get_alphabet(), this);
         orig_symbol_count = symbol_count = alphabet.get_orig_symbol_count();
+        global_flag_state = alphabet.get_fd_table();
         encoder = new Encoder(alphabet.get_symbol_table(), orig_symbol_count);
         TransducerTable<TransitionW> transitions = backend->copy_transitionw_table();
         TransducerTable<TransitionWIndex> indices = backend->copy_windex_table();
@@ -421,6 +475,7 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
             transitions.get_vector(),
             indices.get_vector(),
             alphabet,
+            "TOP",
             this);
         if (transducers[0].get_type() != hfst::HFST_OLW_TYPE) {
             // clean up if we needed a temp transducer
@@ -485,6 +540,7 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
         // this will be the alphabet of the entire container
         alphabet = PmatchAlphabet(harmonized_tmp->get_alphabet(), this);
         orig_symbol_count = symbol_count = alphabet.get_orig_symbol_count();
+        global_flag_state = alphabet.get_fd_table();
         encoder = new Encoder(alphabet.get_symbol_table(), orig_symbol_count);
         TransducerTable<TransitionW> transitions = harmonized_tmp->copy_transitionw_table();
         TransducerTable<TransitionWIndex> indices = harmonized_tmp->copy_windex_table();
@@ -492,6 +548,7 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
             transitions.get_vector(),
             indices.get_vector(),
             alphabet,
+            "TOP",
             this);
         // Then we do the same for the other transducers except without
         // alphabets or encoders because those should be identical
@@ -511,6 +568,7 @@ PmatchContainer::PmatchContainer(std::vector<HfstTransducer> transducers):
                     transitions.get_vector(),
                     indices.get_vector(),
                     alphabet,
+                    temporaries[i]->get_name(),
                     this);
                 alphabet.add_rtn(rtn, temporaries[i]->get_name());
             }
@@ -539,6 +597,7 @@ void PmatchContainer::add_rtn(Transducer * rtn, const std::string & name)
         transitions.get_vector(),
         indices.get_vector(),
         alphabet,
+        name,
         this);
     if (!alphabet.has_rtn(name)) {
         alphabet.add_rtn(pmatch_rtn, name);
@@ -563,15 +622,26 @@ bool PmatchAlphabet::is_end_tag(const SymbolNumber symbol) const
     return end_tag_map.count(symbol) == 1;
 }
 
-bool PmatchAlphabet::is_like_arc(const std::string & symbol)
+bool PmatchAlphabet::is_capture_tag(const std::string & symbol)
 {
-    return symbol.find("@PMATCH_LIKE_") == 0 &&
+    return symbol.find("@PMATCH_CAPTURE_") == 0 &&
         symbol.rfind("@") == symbol.size() - 1;
 }
 
-bool PmatchAlphabet::is_like_arc(const SymbolNumber symbol) const
+bool PmatchAlphabet::is_capture_tag(const SymbolNumber symbol) const
 {
-    return words_like_map.count(symbol) == 1;
+    return capture2captured[symbol] != NO_SYMBOL_NUMBER;
+}
+
+bool PmatchAlphabet::is_captured_tag(const std::string & symbol)
+{
+    return symbol.find("@PMATCH_CAPTURED_") == 0 &&
+        symbol.rfind("@") == symbol.size() - 1;
+}
+
+bool PmatchAlphabet::is_captured_tag(const SymbolNumber symbol) const
+{
+    return captured2capture[symbol] != NO_SYMBOL_NUMBER;
 }
 
 bool PmatchAlphabet::is_insertion(const std::string & symbol)
@@ -591,19 +661,31 @@ bool PmatchAlphabet::is_counter(const std::string & symbol)
 
 bool PmatchAlphabet::is_list(const std::string & symbol)
 {
-    return (symbol.find("@L.") == 0 || symbol.find("@X.") == 0) && symbol.rfind("@") == symbol.size() - 1;
+    return (symbol.find("@L.") == 0 || symbol.find("@X.") == 0) && symbol.rfind("_@") == symbol.size() - 2;
+}
+
+bool PmatchAlphabet::is_global_flag(const std::string & symbol)
+{
+    return (symbol.find("@P.") == 0 || symbol.find("@C.") == 0) && symbol.find("PMATCH_GLOBAL_") == 3 &&
+        symbol.rfind("@") == symbol.size() - 1;
+}
+
+bool PmatchAlphabet::is_global_flag(SymbolNumber symbol)
+{
+    return global_flags[symbol];
 }
 
 bool PmatchAlphabet::is_special(const std::string & symbol)
 {
-    if (symbol.size() == 0) {
+    if (symbol.size() < 3) {
         return false;
     }
     if (is_insertion(symbol) || symbol == "@BOUNDARY@") {
 //        || symbol == "@_UNKNOWN_SYMBOL_@" || symbol == "@_IDENTITY_SYMBOL_@"
         return true;
     } else {
-        return symbol.find("@PMATCH") == 0 && symbol.at(symbol.size() - 1) == '@';
+        return (symbol.find("@PMATCH") == 0 && symbol.at(symbol.size() - 1) == '@')
+            || is_list(symbol);
     }
 }
 
@@ -724,6 +806,24 @@ std::map<std::string, std::string> PmatchContainer::parse_hfst3_header(std::istr
     }
 }
 
+void PmatchContainer::push_rtn_call(unsigned int return_index, PmatchTransducer * caller)
+{
+    RtnStackFrame new_top;
+    new_top.caller = caller;
+    new_top.caller_index = return_index;
+    rtn_stack.push_back(new_top);
+}
+
+RtnStackFrame PmatchContainer::rtn_stack_top(void)
+{
+    return rtn_stack.back();
+}
+
+void PmatchContainer::rtn_stack_pop(void)
+{
+    rtn_stack.pop_back();
+}
+
 void PmatchAlphabet::add_rtn(PmatchTransducer * rtn, std::string const & name)
 {
     SymbolNumber symbol = rtn_names[name];
@@ -732,7 +832,21 @@ void PmatchAlphabet::add_rtn(PmatchTransducer * rtn, std::string const & name)
 
 bool PmatchAlphabet::has_rtn(std::string const & name) const
 {
-    return rtn_names.at(name) < rtns.size() && rtns[rtn_names.at(name)] != NULL;
+    if (name == "TOP") {
+        return true;
+    }
+#ifdef NO_CPLUSPLUS_11
+    hfst_ol::RtnNameMap::const_iterator it = rtn_names.find(name);
+    if (it != rtn_names.end())
+    {
+        return it->second < rtns.size() && rtns[it->second] != NULL;
+    } else {
+        return false;
+    }
+#else	
+    return rtn_names.count(name) != 0 &&
+        rtn_names.at(name) < rtns.size() && rtns[rtn_names.at(name)] != NULL;
+#endif
 }
 
 bool PmatchAlphabet::has_rtn(SymbolNumber symbol) const
@@ -745,6 +859,11 @@ PmatchTransducer * PmatchAlphabet::get_rtn(SymbolNumber symbol)
     return rtns[symbol];
 }
 
+PmatchTransducer * PmatchAlphabet::get_rtn(std::string name)
+{
+    return rtns[rtn_names[name]];
+}
+
 std::string PmatchAlphabet::get_counter_name(SymbolNumber symbol)
 {
     if (symbol_table.size() <= symbol) {
@@ -768,15 +887,23 @@ void PmatchContainer::process(const std::string & input_str)
     initialize_input(input_str.c_str());
     unsigned int input_pos = 0;
     unsigned int printable_input_pos = 0;
+    running_weight = 0.0;
+    stack_depth = 0;
+    best_input_pos = 0;
 
     ++line_number;
-    output.clear();
+    result.clear();
     locations.clear();
+    old_captures.clear();
+    best_captures.clear();
+    captures.clear();
+    reset_recursion();
     DoubleTape nonmatching_locations;
     while (has_queued_input(input_pos)) {
+        best_result.clear();
         SymbolNumber current_input = input[input_pos];
         if (not_possible_first_symbol(current_input)) {
-            copy_to_output(current_input, current_input);
+            copy_to_result(current_input, current_input);
             ++input_pos;
             if (locate_mode && alphabet.is_printable(current_input)) {
                 ++printable_input_pos;
@@ -786,12 +913,14 @@ void PmatchContainer::process(const std::string & input_str)
             continue;
         }
         tape.clear();
+        tape_locations.clear();
         unsigned int tape_pos = 0;
         unsigned int old_input_pos = input_pos;
         toplevel->match(input_pos, tape_pos);
-        if (tape_pos > 0) {
-            // Tape moved
+        if (candidate_found()) {
+            // We got some output
             if (locate_mode) {
+                // First we put into the locations vector all the nonmatching parts we've seen
                 if (!nonmatching_locations.empty()) {
                     LocationVector ls;
                     Location nonmatching = alphabet.locatefy(printable_input_pos - hfst::size_t_to_uint(nonmatching_locations.size()),
@@ -802,21 +931,23 @@ void PmatchContainer::process(const std::string & input_str)
                     nonmatching_locations.clear();
                 }
                 LocationVector ls;
-                for (WeightedDoubleTapeVector::iterator it = (toplevel->locations)->begin();
-                     it != (toplevel->locations)->end(); ++it) {
+                for (WeightedDoubleTapeVector::iterator it = tape_locations.begin();
+                     it != tape_locations.end(); ++it) {
                     ls.push_back(alphabet.locatefy(printable_input_pos,
-                                                          *it));
+                                                   *it));
                 }
                 sort(ls.begin(), ls.end());
                 locations.push_back(ls);
-                printable_input_pos += (input_pos - old_input_pos);
+                printable_input_pos += (best_input_pos - old_input_pos);
             } else {
-                copy_to_output(toplevel->get_best_result());
+                copy_to_result(best_result);
             }
+            input_pos = best_input_pos;
+            old_captures.insert(old_captures.end(), best_captures.begin(), best_captures.end());
         }
-        if (tape_pos == 0 || input_pos == old_input_pos) {
-            // If nothing happened, we move one position up
-            copy_to_output(current_input, current_input);
+        if (!candidate_found() || input_pos == old_input_pos) {
+            // If no input was consumed, we move one position up
+            copy_to_result(current_input, current_input);
             ++input_pos;
             if (locate_mode && alphabet.is_printable(current_input)) {
                 ++printable_input_pos;
@@ -845,7 +976,7 @@ std::string PmatchContainer::match(const std::string & input,
     }
     locate_mode = false;
     process(input);
-    return stringify_output();
+    return alphabet.stringify(result);
 }
 
 LocationVectorVector PmatchContainer::locate(const std::string & input,
@@ -926,35 +1057,29 @@ std::string PmatchContainer::get_pattern_count_info(void)
     return retval;
 }
 
-void PmatchContainer::copy_to_output(const DoubleTape & best_result)
+void PmatchContainer::copy_to_result(const DoubleTape & best_result)
 {
     for (DoubleTape::const_iterator it = best_result.begin();
          it != best_result.end(); ++it) {
-        output.push_back(*it);
+        result.push_back(*it);
     }
 }
 
-void PmatchContainer::copy_to_output(SymbolNumber input_sym, SymbolNumber output_sym)
-{
-    output.push_back(SymbolPair(input_sym, output_sym));
-}
-
-std::string PmatchContainer::stringify_output(void)
+void PmatchContainer::copy_to_result(SymbolNumber input_sym, SymbolNumber output_sym)
 {
-    return alphabet.stringify(output);
+    result.push_back(SymbolPair(input_sym, output_sym));
 }
 
-//LocationVector PmatchContainer::locatefy_output(void)
-//{
-//    return alphabet.locatefy(output);
-//}
-
 std::string PmatchAlphabet::stringify(const DoubleTape & str)
 {
     std::string retval;
     std::stack<unsigned int> start_tag_pos;
+    bool input_contained_printable_symbol = false;
     for (DoubleTape::const_iterator it = str.begin();
          it != str.end(); ++it) {
+        if (!input_contained_printable_symbol && is_printable(it->input)) {
+            input_contained_printable_symbol = true;
+        }
         SymbolNumber output = it->output;
         if (output == special_symbols[entry]) {
             start_tag_pos.push(hfst::size_t_to_uint(retval.size()));
@@ -963,7 +1088,7 @@ std::string PmatchAlphabet::stringify(const DoubleTape & str)
                 start_tag_pos.pop();
             }
         } else if (is_end_tag(output)) {
-            if (container->count_patterns) {
+            if (container->count_patterns && input_contained_printable_symbol) {
                 if ((container->pattern_counts).count(start_tag(output)) == 0) {
                     (container->pattern_counts)[start_tag(output)] = 1;
                 } else {
@@ -972,7 +1097,7 @@ std::string PmatchAlphabet::stringify(const DoubleTape & str)
             }
             unsigned int pos;
             if (start_tag_pos.size() == 0) {
-                std::cerr << "Warning: end tag without start tag\n";
+                std::cerr << "pmatch: warning: end tag without start tag\n";
                 pos = 0;
             } else {
                 pos = start_tag_pos.top();
@@ -980,7 +1105,7 @@ std::string PmatchAlphabet::stringify(const DoubleTape & str)
             if (container->delete_patterns) {
                 size_t how_much_to_delete = retval.size() - pos;
                 retval.replace(pos, how_much_to_delete, start_tag(output));
-            } else if (container->mark_patterns) {
+            } else if (container->mark_patterns && input_contained_printable_symbol) {
                 retval.insert(pos, start_tag(output));
                 retval.append(end_tag(output));
             }
@@ -1060,38 +1185,47 @@ std::string PmatchContainer::get_unsatisfied_rtn_name(void) const
 
 bool PmatchContainer::has_queued_input(unsigned int input_pos)
 {
-    return input_pos < input.size();
+    // we catch underflow due to left context checking here
+    return input_pos < input.size() && (input_pos + 1 != 0);
+}
+
+bool PmatchContainer::input_matches_at(unsigned int pos,
+                                       SymbolNumberVector::iterator begin,
+                                       SymbolNumberVector::iterator end)
+{
+    if (pos + (end - begin) > input.size()) {
+        return false;
+    }
+    for (size_t i = 0; begin + i != end; ++i) {
+        if (input[pos + i] != *(begin + i)) {
+            return false;
+        }
+    }
+    return true;
 }
 
 PmatchTransducer::PmatchTransducer(std::istream & is,
                                    TransitionTableIndex index_table_size,
                                    TransitionTableIndex transition_table_size,
                                    PmatchAlphabet & alpha,
+                                   std::string _name,
                                    PmatchContainer * cont):
     alphabet(alpha),
-    container(cont),
-    locations(NULL)
+    name(_name),
+    container(cont)
 {
     orig_symbol_count = hfst::size_t_to_uint(alphabet.get_symbol_table().size());
     // initialize the stack for local variables
-    LocalVariables locals_front;
-    locals_front.flag_state = alphabet.get_fd_table();
-    locals_front.tape_step = 1;
-    locals_front.max_context_length_remaining = 254;
-    locals_front.context = none;
-    locals_front.context_placeholder = 0;
-    locals_front.default_symbol_trap = false;
-    locals_front.negative_context_success = false;
-    locals_front.pending_passthrough = false;
-    locals_front.running_weight = 0.0;
-    local_stack.push(locals_front);
-    RtnVariables rtn_front;
-    rtn_front.tape_entry = 0;
-    rtn_front.input_tape_entry = 0;
-    rtn_front.candidate_input_pos = 0;
-    rtn_front.candidate_tape_pos = 0;
-    rtn_stack.push(rtn_front);
-
+    LocalVariables local_variables;
+    local_variables.flag_state = alphabet.get_fd_table();
+    local_variables.tape_step = 1;
+    local_variables.max_context_length_remaining = 254;
+    local_variables.context = none;
+    local_variables.context_placeholder = 0;
+    local_variables.default_symbol_trap = false;
+    local_variables.negative_context_success = false;
+    local_variables.pending_passthrough = false;
+    local_stack.push(local_variables);
 
     // Allocate and read tables
     char * indextab = (char*) malloc(TransitionWIndex::size * index_table_size);
@@ -1101,10 +1235,6 @@ PmatchTransducer::PmatchTransducer(std::istream & is,
     char * orig_p = indextab;
     index_table.reserve(index_table_size);
     while(index_table_size) {
-        // index_table.push_back(
-        //     SimpleIndex(*(SymbolNumber *) indextab,
-        //                 *(TransitionTableIndex *) (indextab + sizeof(SymbolNumber))));
-        // --index_table_size;
         index_table.push_back(TransitionWIndex(indextab));
         --index_table_size;
         indextab += TransitionWIndex::size;
@@ -1114,9 +1244,6 @@ PmatchTransducer::PmatchTransducer(std::istream & is,
     transition_table.reserve(transition_table_size);
     while(transition_table_size) {
         transition_table.push_back(TransitionW(transitiontab));
-            // SimpleTransition(*(SymbolNumber *) transitiontab,
-            //                  *(SymbolNumber *) (transitiontab + sizeof(SymbolNumber)),
-            //                  *(TransitionTableIndex *) (transitiontab + 2*sizeof(SymbolNumber))));
         --transition_table_size;
         transitiontab += TransitionW::size;
     }
@@ -1126,32 +1253,26 @@ PmatchTransducer::PmatchTransducer(std::istream & is,
 PmatchTransducer::PmatchTransducer(std::vector<TransitionW> transition_vector,
                                    std::vector<TransitionWIndex> index_vector,
                                    PmatchAlphabet & alpha,
+                                   std::string _name,
                                    PmatchContainer * cont):
     transition_table(transition_vector),
     index_table(index_vector),
     alphabet(alpha),
-    container(cont),
-    locations(NULL)
+    name(_name),
+    container(cont)
 {
     orig_symbol_count = hfst::size_t_to_uint(alphabet.get_symbol_table().size());
     // initialize the stack for local variables
-    LocalVariables locals_front;
-    locals_front.flag_state = alphabet.get_fd_table();
-    locals_front.tape_step = 1;
-    locals_front.max_context_length_remaining = 254;
-    locals_front.context = none;
-    locals_front.context_placeholder = 0;
-    locals_front.default_symbol_trap = false;
-    locals_front.negative_context_success = false;
-    locals_front.pending_passthrough = false;
-    locals_front.running_weight = 0.0;
-    local_stack.push(locals_front);
-    RtnVariables rtn_front;
-    rtn_front.tape_entry = 0;
-    rtn_front.input_tape_entry = 0;
-    rtn_front.candidate_input_pos = 0;
-    rtn_front.candidate_tape_pos = 0;
-    rtn_stack.push(rtn_front);
+    LocalVariables local_variables;
+    local_variables.flag_state = alphabet.get_fd_table();
+    local_variables.tape_step = 1;
+    local_variables.max_context_length_remaining = 254;
+    local_variables.context = none;
+    local_variables.context_placeholder = 0;
+    local_variables.default_symbol_trap = false;
+    local_variables.negative_context_success = false;
+    local_variables.pending_passthrough = false;
+    local_stack.push(local_variables);
 }
 
 // Precompute which symbols may be at the start of a match.
@@ -1167,7 +1288,6 @@ void PmatchTransducer::collect_possible_first_symbols(void)
     for (SymbolNumber i = 1; i < symbol_count; ++i) {
         if (!alphabet.is_like_epsilon(i) &&
             !alphabet.is_end_tag(i) &&
-            !alphabet.is_like_arc(i) &&
             special_symbols.count(i) == 0 &&
             i != alphabet.get_unknown_symbol() &&
             i != alphabet.get_identity_symbol() &&
@@ -1210,14 +1330,12 @@ void PmatchTransducer::collect_first_epsilon(TransitionTableIndex i,
                 } else {
                     // We're going to fake through a context
                     collect_first(transition_table[i].get_target(), input_symbols, seen_indices);
-                    local_stack.pop();
                     ++i;
                 }
             } else {
                 // We *are* checking context and may be done
                 if (try_exiting_context(output)) {
                     collect_first(transition_table[i].get_target(), input_symbols, seen_indices);
-                    local_stack.pop();
                     ++i;
                 } else {
                     // Don't touch output when checking context
@@ -1354,6 +1472,7 @@ void PmatchContainer::set_properties(void)
     max_context_length = 254;
     max_recursion = 5000;
     need_separators = true;
+    xerox_composition = true;
 }
 
 void PmatchContainer::set_properties(std::map<std::string, std::string> & properties)
@@ -1412,6 +1531,12 @@ void PmatchContainer::set_properties(std::map<std::string, std::string> & proper
             } else if (it->second == "off") {
                 need_separators = false;
             }
+        } else if (it->first == "xerox-composition") {
+            if (it->second == "off") {
+                xerox_composition = false;
+            } else if (it->second == "on") {
+                xerox_composition = true;
+            }
         }
     }
 }
@@ -1478,112 +1603,134 @@ void PmatchContainer::initialize_input(const char * input_s)
     return;
 }
 
-void PmatchTransducer::match(unsigned int & input_tape_pos,
-                             unsigned int & tape_pos)
+void PmatchTransducer::match(unsigned int input_tape_pos,
+                             unsigned int tape_pos)
 {
-    rtn_stack.top().best_result.clear();
-    rtn_stack.top().candidate_input_pos = input_tape_pos;
-    rtn_stack.top().input_tape_entry = input_tape_pos;
-    rtn_stack.top().tape_entry = tape_pos;
-    rtn_stack.top().candidate_tape_pos = tape_pos;
-    rtn_stack.top().best_weight = 0.0;
-    rtn_stack.top().candidate_found = false;
     local_stack.top().context = none;
     local_stack.top().tape_step = 1;
     local_stack.top().context_placeholder = 0;
     local_stack.top().default_symbol_trap = false;
-    local_stack.top().running_weight = 0.0;
-    if (locations != NULL) {
-        delete locations;
-        locations = NULL;
-    }
-    if (container->locate_mode) {
-        locations = new WeightedDoubleTapeVector();
-    }
     get_analyses(input_tape_pos, tape_pos, 0);
-    tape_pos = rtn_stack.top().candidate_tape_pos;
-    input_tape_pos = rtn_stack.top().candidate_input_pos;
-}
-
-void PmatchTransducer::rtn_call(unsigned int & input_tape_pos,
-                                unsigned int & tape_pos)
-{
-    rtn_stack.push(rtn_stack.top());
-    rtn_stack.top().candidate_input_pos = input_tape_pos;
-    rtn_stack.top().input_tape_entry = input_tape_pos;
-    rtn_stack.top().tape_entry = tape_pos;
-    rtn_stack.top().candidate_tape_pos = tape_pos;
-    rtn_stack.top().best_weight = 0.0;
-    rtn_stack.top().candidate_found = false;
-    local_stack.push(local_stack.top());
-    local_stack.top().flag_state = alphabet.get_fd_table();
-    local_stack.top().tape_step = 1;
-    local_stack.top().context = none;
-    local_stack.top().context_placeholder = 0;
-    local_stack.top().default_symbol_trap = false;
-    local_stack.top().running_weight = 0.0;
-    get_analyses(input_tape_pos, tape_pos, 0);
-    tape_pos = rtn_stack.top().candidate_tape_pos;
-    input_tape_pos = rtn_stack.top().candidate_input_pos;
 }
 
-void PmatchTransducer::rtn_exit(void)
-{
-    rtn_stack.pop();
+void PmatchTransducer::rtn_call(unsigned int input_tape_pos,
+                                unsigned int tape_pos,
+                                PmatchTransducer * caller,
+                                TransitionTableIndex caller_index)
+{
+    container->increase_stack_depth();
+    LocalVariables new_top(local_stack.top());
+    new_top.flag_state = alphabet.get_fd_table();
+    new_top.tape_step = 1;
+    new_top.context = none;
+    new_top.context_placeholder = 0;
+    new_top.default_symbol_trap = false;
+    local_stack.push(new_top);
+    container->push_rtn_call(caller_index, caller);
+    get_analyses(input_tape_pos, tape_pos, 0);
     local_stack.pop();
+    container->rtn_stack_pop();
+    container->decrease_stack_depth();
+}
+
+void PmatchTransducer::rtn_return(unsigned int input_tape_pos,
+                                  unsigned int tape_pos)
+{
+    LocalVariables new_top(local_stack.top());
+    TransitionTableIndex entry_index = container->rtn_stack.at(container->get_stack_depth() - 1).caller_index;
+    new_top.flag_state = alphabet.get_fd_table();
+    new_top.tape_step = 1;
+    new_top.context = none;
+    new_top.context_placeholder = 0;
+    new_top.default_symbol_trap = false;
+    local_stack.push(new_top);
+    container->decrease_stack_depth();
+    get_analyses(input_tape_pos, tape_pos, entry_index);
+    local_stack.pop();
+    container->increase_stack_depth();
 }
 
-void PmatchTransducer::note_analysis(unsigned int input_pos,
-                                     unsigned int tape_pos)
+void PmatchTransducer::handle_final_state(unsigned int input_pos,
+                                          unsigned int tape_pos)
 {
-    if (input_pos + 1 == 0) {
-        // Sanity check for tape beyond its limits, this can happen
-        // with left contexts and should be dealt with a bit more nicely
-        return;
-    }
-    rtn_stack.top().candidate_found = true;
-    if (locations != NULL) {
-        grab_location(input_pos, tape_pos);
-        return;
+    if (container->get_stack_depth() > 0) {
+        // We're not the toplevel, return to caller
+        PmatchTransducer * rtn_target =  container->
+            rtn_stack.at(container->get_stack_depth() - 1).caller;
+        rtn_target->rtn_return(input_pos, tape_pos);
+    } else if (container->is_in_locate_mode()) {
+        container->grab_location(input_pos, tape_pos);
+    } else {
+        container->note_analysis(input_pos, tape_pos);
     }
-    
-    if ((input_pos > rtn_stack.top().candidate_input_pos) ||
-        (input_pos == rtn_stack.top().candidate_input_pos &&
-         rtn_stack.top().best_weight > local_stack.top().running_weight)) {
-        rtn_stack.top().best_result = container->tape.extract_slice(
-            rtn_stack.top().tape_entry, tape_pos);
-        rtn_stack.top().candidate_tape_pos = tape_pos;
-        rtn_stack.top().candidate_input_pos = input_pos;
-        rtn_stack.top().best_weight = local_stack.top().running_weight;
-    } else if (container->verbose &&
-               input_pos == rtn_stack.top().candidate_input_pos &&
-               rtn_stack.top().best_weight == local_stack.top().running_weight) {
-        DoubleTape discarded(container->tape.extract_slice(
-                                 rtn_stack.top().tape_entry, tape_pos));
-        std::cerr << "\n\tline " << container->line_number << ": conflicting equally weighted matches found, keeping:\n\t"
-                  << alphabet.stringify(rtn_stack.top().best_result) << std::endl
+}
+
+void PmatchContainer::note_analysis(unsigned int input_pos, unsigned int tape_pos)
+{
+    if ((input_pos > best_input_pos) ||
+        (input_pos == best_input_pos &&
+         best_weight > running_weight)) {
+        best_result = tape.extract_slice(0, tape_pos);
+        best_captures = captures;
+        best_input_pos = input_pos;
+        best_weight = running_weight;
+    } else if (verbose &&
+               input_pos == best_input_pos &&
+               best_weight == running_weight) {
+        DoubleTape discarded(tape.extract_slice(0, tape_pos));
+        std::cerr << "\n\tline " << line_number << ": conflicting equally weighted matches found, keeping:\n\t"
+                  << alphabet.stringify(best_result) << std::endl
                   << "\tdiscarding:\n\t"
                   << alphabet.stringify(discarded) << std::endl << std::endl;
     }
 }
 
-void PmatchTransducer::grab_location(unsigned int input_pos, unsigned int tape_pos)
+void PmatchContainer::grab_location(unsigned int input_pos, unsigned int tape_pos)
 {
-    if (locations->size() != 0) {
-        if (input_pos < rtn_stack.top().candidate_input_pos) {
+    if (tape_locations.size() != 0) {
+        if (input_pos < best_input_pos) {
             // We already have better matches
             return;
-        } else if (input_pos > rtn_stack.top().candidate_input_pos) {
+        } else if (input_pos > best_input_pos) {
             // The old locations are worse
-            locations->clear();
+            best_captures.clear();
+            tape_locations.clear();
         }
     }
-    rtn_stack.top().candidate_tape_pos = tape_pos;
-    rtn_stack.top().candidate_input_pos = input_pos;
-    WeightedDoubleTape rv(container->tape.extract_slice(
-                              rtn_stack.top().tape_entry, tape_pos),
-                          local_stack.top().running_weight);
-    locations->push_back(rv);
+    best_input_pos = input_pos;
+    best_captures = captures;
+    WeightedDoubleTape rv(tape.extract_slice(0, tape_pos), running_weight);
+    tape_locations.push_back(rv);
+}
+
+std::pair<SymbolNumberVector::iterator,
+          SymbolNumberVector::iterator> PmatchContainer::get_longest_matching_capture(
+    SymbolNumber key, unsigned int input_pos)
+{
+    std::pair<SymbolNumberVector::iterator, SymbolNumberVector::iterator> longest_so_far(input.begin(), input.begin());
+    for (std::vector<Capture>::iterator it =
+             captures.begin(); it != captures.end(); ++it) {
+        if (key == it->name && input_matches_at(input_pos, input.begin() + it->begin, input.begin() + it->end)) {
+            if ((it->end - it->begin) <= longest_so_far.second - longest_so_far.first) {
+                continue;
+            } else {
+                longest_so_far.first = input.begin() + it->begin;
+                longest_so_far.second = input.begin() + it->end;
+            }
+        }
+    }
+    for (std::vector<Capture>::iterator it =
+             old_captures.begin(); it != old_captures.end(); ++it) {
+        if (key == it->name && input_matches_at(input_pos, input.begin() + it->begin, input.begin() + it->end)) {
+            if ((it->end - it->begin) <= longest_so_far.second - longest_so_far.first) {
+                continue;
+            } else {
+                longest_so_far.first = input.begin() + it->begin;
+                longest_so_far.second = input.begin() + it->end;
+            }
+        }
+    }
+    return longest_so_far;
 }
 
 void PmatchTransducer::take_epsilons(unsigned int input_pos,
@@ -1591,13 +1738,13 @@ void PmatchTransducer::take_epsilons(unsigned int input_pos,
                                      TransitionTableIndex i)
 {
     i = make_transition_table_index(i, 0);
-    
     while (is_good(i)) {
         SymbolNumber input = transition_table[i].get_input_symbol();
         SymbolNumber output = transition_table[i].get_output_symbol();
         TransitionTableIndex target = transition_table[i].get_target();
-        Weight weight = transition_table[i].get_weight();
-        // We handle paths where we're checking contexts here
+        Weight old_weight = container->get_weight();
+        container->increment_weight(transition_table[i].get_weight());
+        // We also handle paths where we're checking contexts here
         if (input == 0) {
             if (container->profile_mode) {
                 alphabet.count(output);
@@ -1606,27 +1753,43 @@ void PmatchTransducer::take_epsilons(unsigned int input_pos,
                 if (!try_entering_context(output)) {
                     // no context to enter, regular input epsilon
                     container->tape.write(tape_pos, 0, output);
-                    Weight old_weight = local_stack.top().running_weight;
-                    local_stack.top().running_weight += weight;
-
+                    
                     // if it's an entry or exit arc, adjust entry stack
                     if (output == alphabet.get_special(entry)) {
                         container->entry_stack.push(input_pos);
                     } else if (output == alphabet.get_special(exit)) {
                         container->entry_stack.pop();
-                    } else if (alphabet.is_like_arc(output)) { // a Like() arc
-                        match_like_arc(input_pos, tape_pos);
+                    } else if (alphabet.is_capture_tag(output)) {
+                        // if it's a capture tag, remember where we were
+                        Capture capture;
+                        capture.begin = container->entry_stack.back();
+                        capture.end = input_pos;
+                        capture.name = output;
+                        container->captures.push_back(capture);
+                    } else if (alphabet.is_captured_tag(output)) {
+                        // if it's a captured tag, try each previously
+                        // captured sequence
+                        std::pair<SymbolNumberVector::iterator, SymbolNumberVector::iterator> cap =
+                            container->get_longest_matching_capture(alphabet.captured2capture[output], input_pos);
+                        if (cap.second - cap.first != 0) {
+                            container->tape.write(tape_pos, cap);
+                            get_analyses(input_pos + (cap.second - cap.first),
+                                         tape_pos + (cap.second - cap.first), target);
+                        }
+                        ++i;
+                        container->set_weight(old_weight);
+                        continue;
                     }
                     
                     get_analyses(input_pos, tape_pos + 1, target);
-
+                    
                     if (output == alphabet.get_special(entry)) {
-                        container->entry_stack.pop();
+                        container->entry_stack.pop_back();
                     } else if (output == alphabet.get_special(exit)) {
                         container->entry_stack.unpop();
+                    } else if (alphabet.is_capture_tag(output)) {
+                        container->captures.pop_back();
                     }
-                    
-                    local_stack.top().running_weight = old_weight;
                 } else {
                     check_context(input_pos, tape_pos, i);
                 }
@@ -1649,11 +1812,13 @@ void PmatchTransducer::take_epsilons(unsigned int input_pos,
         } else if (alphabet.is_flag_diacritic(input)) {
             take_flag(input, input_pos, tape_pos, i);
         } else if (alphabet.has_rtn(input)) {
-            take_rtn(input, input_pos, tape_pos, i);
+            alphabet.get_rtn(input)->rtn_call(input_pos, tape_pos, this, target);
         } else { // it's not epsilon and it's not a flag or Ins, so nothing to do
+            container->set_weight(old_weight);
             return;
         }
         ++i;
+        container->set_weight(old_weight);
     }
 }
 
@@ -1661,6 +1826,9 @@ void PmatchTransducer::check_context(unsigned int input_pos,
                                      unsigned int tape_pos,
                                      TransitionTableIndex i)
 {
+    // The context placeholder remembers the position in the input before
+    // a context check. If the context check is successful, the placeholder
+    // will be used as the input position going forwards.
     local_stack.top().context_placeholder = input_pos;
     if (local_stack.top().context == LC ||
         local_stack.top().context == NLC) {
@@ -1668,74 +1836,46 @@ void PmatchTransducer::check_context(unsigned int input_pos,
         input_pos = container->entry_stack.top() - 1;
     }
     get_analyses(input_pos, tape_pos, transition_table[i].get_target());
+
+
     // In case we have a negative context, we check to see if the context matched.
-    // If it did, we schedule a passthrough arc after we've processed epsilons.
+    // If it didn't, we schedule a passthrough arc after we've processed epsilons.
     bool schedule_passthrough = false;
-//            std::cerr << "!local_stack.top().negative_context_success is " <<
-//            !local_stack.top().negative_context_success << std::endl;
-
-    if((local_stack.top().context == NLC || local_stack.top().context == NRC)
-       && !local_stack.top().negative_context_success) {
-        schedule_passthrough = true;
-//        std::cerr << "scheduled passthrough\n";
+    if(local_stack.top().context == NLC || local_stack.top().context == NRC) {
+        if (local_stack.top().negative_context_success == false) {
+            schedule_passthrough = true;
+        }
     }
+// Pop the local stack that got pushed by entering the context
     local_stack.pop();
     if (schedule_passthrough) {
         local_stack.top().pending_passthrough = true;
     }
 }
 
-void PmatchTransducer::take_rtn(SymbolNumber input,
-                                unsigned int input_pos,
-                                unsigned int tape_pos,
-                                TransitionTableIndex i)
-{
-    unsigned int original_tape_pos = tape_pos;
-    Weight original_weight = local_stack.top().running_weight;
-    local_stack.top().running_weight += transition_table[i].get_weight();
-    // Pass control
-    PmatchTransducer * rtn_target =
-        alphabet.get_rtn(input);
-    rtn_target->rtn_call(input_pos, tape_pos);
-    if (tape_pos != original_tape_pos) {
-        // Tape moved, fetch result
-        tape_pos = original_tape_pos;
-        for(DoubleTape::const_iterator it =
-                rtn_target->get_best_result().begin();
-            it != rtn_target->get_best_result().end();
-            ++it) {
-            container->tape.write(tape_pos++, it->input, it->output);
-        }
-        local_stack.top().running_weight += rtn_target->get_best_weight();
-        rtn_target->rtn_exit();
-        // We're back in this transducer and continue where we left off
-        get_analyses(input_pos, tape_pos, transition_table[i].get_target());
-    } else {
-        rtn_target->rtn_exit();
-    }
-    local_stack.top().running_weight = original_weight;
-}
-
-void PmatchTransducer::match_like_arc(unsigned int input_pos,
-                                      unsigned int tape_pos)
-{
-}
-
 void PmatchTransducer::take_flag(SymbolNumber input,
                                  unsigned int input_pos,
                                  unsigned int tape_pos,
                                  TransitionTableIndex i)
 {
+    std::vector<short> old_global_values;
+    if (alphabet.is_global_flag(input)) {
+        (old_global_values = container->global_flag_state.get_values());
+        if (((container->global_flag_state).apply_operation
+             (*(alphabet.get_operation(input)))) == false) {
+            return;
+        }
+    }
     std::vector<short> old_values(local_stack.top().flag_state.get_values());
     if (local_stack.top().flag_state.apply_operation(
             *(alphabet.get_operation(input)))) {
         // flag diacritic allowed
         // generally we shouldn't care to write flags
 //                container->tape.write(tape_pos, input, output);
-        Weight old_weight = local_stack.top().running_weight;
-        local_stack.top().running_weight += transition_table[i].get_weight();
         get_analyses(input_pos, tape_pos, transition_table[i].get_target());
-        local_stack.top().running_weight = old_weight;
+    }
+    if (alphabet.is_global_flag(input)) {
+        (container->global_flag_state).assign_values(old_global_values);
     }
     local_stack.top().flag_state.assign_values(old_values);
 }
@@ -1754,6 +1894,8 @@ void PmatchTransducer::take_transitions(SymbolNumber input,
         if (this_input == NO_SYMBOL_NUMBER) {
             return;
         } else if (this_input == input) {
+            Weight old_weight = container->get_weight();
+            container->increment_weight(transition_table[i].get_weight());
             if (!checking_context()) {
                 if (this_output == alphabet.get_identity_symbol() ||
                     (this_output == alphabet.get_unknown_symbol()) ||
@@ -1767,16 +1909,12 @@ void PmatchTransducer::take_transitions(SymbolNumber input,
                     (alphabet.list2symbols[this_input] != NO_SYMBOL_NUMBER)) {
                     this_input = container->input[input_pos];
                 }
-                Weight tmp = local_stack.top().running_weight;
-                local_stack.top().running_weight +=
-                    transition_table[i].get_weight();
                 if (this_input == alphabet.get_special(Pmatch_passthrough)) {
                     get_analyses(input_pos, tape_pos, target); // awkward
                 } else {
                     container->tape.write(tape_pos, this_input, this_output);
                     get_analyses(input_pos + 1, tape_pos + 1, target);
                 }
-                local_stack.top().running_weight = tmp;
             } else {
                 // Checking context so don't touch output
                 if (local_stack.top().max_context_length_remaining > 0) {
@@ -1786,6 +1924,7 @@ void PmatchTransducer::take_transitions(SymbolNumber input,
                 }
             }
             local_stack.top().default_symbol_trap = false;
+            container->set_weight(old_weight);
         } else {
             return;
         }
@@ -1802,7 +1941,7 @@ void PmatchTransducer::get_analyses(unsigned int input_pos,
         // Have we spent too much time?
         if (container->limit_reached ||
             (container->call_counter % 1000000 == 0 &&
-             (rtn_stack.top().candidate_found &&
+             (container->candidate_found() &&
               // if we have at least something, stop doing more work
               (((double)(clock() - container->start_clock)) / CLOCKS_PER_SEC) > container->max_time))) {
             container->limit_reached = true;
@@ -1817,21 +1956,20 @@ void PmatchTransducer::get_analyses(unsigned int input_pos,
     }
     local_stack.top().default_symbol_trap = true;
     take_epsilons(input_pos, tape_pos, i + 1);
-//    std::cerr << "get_analyses local stack size is " << local_stack.size() << std::endl;
-    if (local_stack.top().pending_passthrough) {
-        // A negative context failed
+    if (local_stack.top().pending_passthrough == true) {
+        local_stack.top().pending_passthrough = false;
+        // A negative context failed (successfully)
         take_transitions(alphabet.get_special(Pmatch_passthrough),
                          input_pos, tape_pos, i+1);
-        local_stack.top().pending_passthrough = false;
     }
     // Check for finality even if the input string hasn't ended
     if (is_final(i)) {
-        Weight tmp = local_stack.top().running_weight;
-        local_stack.top().running_weight += get_weight(i);
-        note_analysis(input_pos, tape_pos);
-        local_stack.top().running_weight = tmp;
+        Weight old_weight = container->get_weight();
+        container->increment_weight(get_weight(i));
+        handle_final_state(input_pos, tape_pos);
+        container->set_weight(old_weight);
     }
-
+    
     SymbolNumber input;
     if (!container->has_queued_input(input_pos)) {
         container->unrecurse();
@@ -1839,7 +1977,7 @@ void PmatchTransducer::get_analyses(unsigned int input_pos,
     } else {
         input = container->input[input_pos];
     }
-    
+
     if (alphabet.symbol2lists[input] != NO_SYMBOL_NUMBER) {
 // At least one symbol list could allow this symbol
         for(SymbolNumberVector::const_iterator it =
@@ -1859,7 +1997,6 @@ void PmatchTransducer::get_analyses(unsigned int input_pos,
             take_transitions(alphabet.get_unknown_symbol(), input_pos, tape_pos, i+1);
         }
     }
-    
     container->unrecurse();
 }
 
@@ -1870,37 +2007,30 @@ bool PmatchTransducer::checking_context(void) const
 
 bool PmatchTransducer::try_entering_context(SymbolNumber symbol)
 {
+    LocalVariables new_top;
     if (symbol == alphabet.get_special(LC_entry)) {
-        local_stack.push(local_stack.top());
-        local_stack.top().context = LC;
-        local_stack.top().tape_step = -1;
-        local_stack.top().max_context_length_remaining =
-            container->max_context_length;
-        return true;
+        new_top = local_stack.top();
+        new_top.context = LC;
+        new_top.tape_step = -1;
     } else if (symbol == alphabet.get_special(RC_entry)) {
-        local_stack.push(local_stack.top());
-        local_stack.top().context = RC;
-        local_stack.top().tape_step = 1;
-        local_stack.top().max_context_length_remaining =
-            container->max_context_length;
-        return true;
+        new_top = local_stack.top();
+        new_top.context = RC;
+        new_top.tape_step = 1;
     } else if (symbol == alphabet.get_special(NLC_entry)) {
-        local_stack.push(local_stack.top());
-        local_stack.top().context = NLC;
-        local_stack.top().tape_step = -1;
-        local_stack.top().max_context_length_remaining =
-            container->max_context_length;
-        return true;
+        new_top = local_stack.top();
+        new_top.context = NLC;
+        new_top.tape_step = -1;
     } else if (symbol == alphabet.get_special(NRC_entry)) {
-        local_stack.push(local_stack.top());
-        local_stack.top().context = NRC;
-        local_stack.top().tape_step = 1;
-        local_stack.top().max_context_length_remaining =
-            container->max_context_length;
-        return true;
+        new_top = local_stack.top();
+        new_top.context = NRC;
+        new_top.tape_step = 1;
     } else {
         return false;
     }
+    new_top.max_context_length_remaining =
+        container->max_context_length;
+    local_stack.push(new_top);
+    return true;
 }
 
 bool PmatchTransducer::try_exiting_context(SymbolNumber symbol)
@@ -1937,10 +2067,11 @@ bool PmatchTransducer::try_exiting_context(SymbolNumber symbol)
 
 void PmatchTransducer::exit_context(void)
 {
-    local_stack.push(local_stack.top());
-    local_stack.top().context = none;
-    local_stack.top().negative_context_success = false;
-    local_stack.top().tape_step = 1;
+    LocalVariables new_top(local_stack.top());
+    new_top.context = none;
+    new_top.negative_context_success = false;
+    new_top.tape_step = 1;
+    local_stack.push(new_top);
 }
 
 }
diff --git a/libhfst/src/implementations/optimized-lookup/pmatch.h b/libhfst/src/implementations/optimized-lookup/pmatch.h
index 626812e..a5d26d5 100644
--- a/libhfst/src/implementations/optimized-lookup/pmatch.h
+++ b/libhfst/src/implementations/optimized-lookup/pmatch.h
@@ -15,6 +15,7 @@
 #include <algorithm>
 #include <ctime>
 #include "HfstTransducer.h"
+#include "HfstExceptionDefs.h"
 #include "transducer.h"
 
 namespace hfst_ol {
@@ -23,7 +24,9 @@ namespace hfst_ol {
     class PmatchContainer;
     struct Location;
     struct WeightedDoubleTape;
+    struct RtnStackFrame;
 
+    typedef std::vector<RtnStackFrame> RtnCallStack;
     typedef std::vector<PmatchTransducer *> RtnVector;
     typedef std::map<std::string, SymbolNumber> RtnNameMap;
     typedef std::vector<Location> LocationVector;
@@ -46,7 +49,6 @@ namespace hfst_ol {
                        Pmatch_input_mark,
                        SPECIALSYMBOL_NR_ITEMS};
 
-
     class PositionStack: public std::vector<unsigned int>
     {
         unsigned int tmp;
@@ -62,7 +64,10 @@ namespace hfst_ol {
         RtnVector rtns;
         SymbolNumberVector special_symbols;
         std::map<SymbolNumber, std::string> end_tag_map;
-        std::map<SymbolNumber, std::string> words_like_map;
+        std::map<std::string, SymbolNumber> capture_tag_map;
+        std::map<std::string, SymbolNumber> captured_tag_map;
+        SymbolNumberVector capture2captured;
+        SymbolNumberVector captured2capture;
         RtnNameMap rtn_names;
 // For each symbol, either NO_SYMBOL for "no corresponding list" or an index into symbol_lists
         SymbolNumberVector symbol2lists;
@@ -76,12 +81,15 @@ namespace hfst_ol {
         std::vector<SymbolNumberVector> symbol_list_members;
         std::vector<unsigned long> counters;
         SymbolNumberVector guards;
+        std::vector<bool> global_flags;
         std::vector<bool> printable_vector;
         bool is_end_tag(const SymbolNumber symbol) const;
+        bool is_capture_tag(const SymbolNumber symbol) const;
+        bool is_captured_tag(const SymbolNumber symbol) const;
         bool is_input_mark(const SymbolNumber symbol) const;
-        bool is_like_arc(const SymbolNumber symbol) const;
         bool is_guard(const SymbolNumber symbol) const;
         bool is_counter(const SymbolNumber symbol) const;
+        bool is_global_flag(const SymbolNumber symbol) const;
         std::string end_tag(const SymbolNumber symbol);
         std::string start_tag(const SymbolNumber symbol);
         PmatchContainer * container;
@@ -93,16 +101,19 @@ namespace hfst_ol {
         ~PmatchAlphabet(void);
         virtual void add_symbol(const std::string & symbol);
         static bool is_end_tag(const std::string & symbol);
-        static bool is_like_arc(const std::string & symbol);
+        static bool is_capture_tag(const std::string & symbol);
+        static bool is_captured_tag(const std::string & symbol);
         static bool is_insertion(const std::string & symbol);
         static bool is_guard(const std::string & symbol);
         static bool is_list(const std::string & symbol);
         static bool is_counter(const std::string & symbol);
         static bool is_special(const std::string & symbol);
         static bool is_printable(const std::string & symbol);
+        static bool is_global_flag(const std::string & symbol);
         static std::string name_from_insertion(
             const std::string & symbol);
         bool is_printable(SymbolNumber symbol);
+        bool is_global_flag(SymbolNumber symbol);
         void add_special_symbol(const std::string & str, SymbolNumber symbol_number);
         void process_symbol_list(std::string str, SymbolNumber sym);
         void process_counter(std::string str, SymbolNumber sym);
@@ -111,6 +122,7 @@ namespace hfst_ol {
         bool has_rtn(std::string const & name) const;
         bool has_rtn(SymbolNumber symbol) const;
         PmatchTransducer * get_rtn(SymbolNumber symbol);
+        PmatchTransducer * get_rtn(std::string name);
         std::string get_counter_name(SymbolNumber symbol);
         SymbolNumber get_special(SpecialSymbol special) const;
         SymbolNumberVector get_specials(void) const;
@@ -122,6 +134,19 @@ namespace hfst_ol {
         friend class PmatchContainer;
     };
 
+    struct RtnStackFrame
+    {
+        PmatchTransducer * caller;
+        TransitionTableIndex caller_index;
+    };
+
+    struct Capture
+    {
+        unsigned int begin;
+        unsigned int end;
+        SymbolNumber name;
+    };
+
     class PmatchContainer
     {
     protected:
@@ -130,13 +155,21 @@ namespace hfst_ol {
         SymbolNumber orig_symbol_count;
         SymbolNumber symbol_count;
         PmatchTransducer * toplevel;
-        size_t io_size;
         SymbolNumberVector input;
+        // This tracks the ENTRY and EXIT tags
         PositionStack entry_stack;
+        RtnCallStack rtn_stack;
         DoubleTape tape;
-        DoubleTape output;
+        DoubleTape best_result;
+        DoubleTape result;
         LocationVectorVector locations;
+        WeightedDoubleTapeVector tape_locations;
+        std::vector<Capture> captures;
+        std::vector<Capture> best_captures;
+        std::vector<Capture> old_captures;
         std::vector<char> possible_first_symbols;
+        // The flag state for global flags
+        hfst::FdState<SymbolNumber> global_flag_state;
         bool verbose;
         
         bool count_patterns;
@@ -147,6 +180,7 @@ namespace hfst_ol {
         size_t max_context_length;
         size_t max_recursion;
         bool need_separators;
+        bool xerox_composition;
 
         unsigned long line_number;
         std::map<std::string, size_t> pattern_counts;
@@ -161,6 +195,15 @@ namespace hfst_ol {
         unsigned long call_counter;
         // A flag to set for when time has been overstepped
         bool limit_reached;
+        // The global running weight
+        Weight running_weight;
+        // This is the depth of the stack from the point of view of the
+        // container. When it's 0, we're in the toplevel, even if the
+        // stack of variables is bigger due to having passed through a RTN.
+        unsigned int stack_depth;
+        // Where in the input the best candidate so far has gotten to
+        unsigned int best_input_pos;
+        Weight best_weight;
 
         void collect_first_symbols(void);
 
@@ -184,9 +227,17 @@ namespace hfst_ol {
                           double time_cutoff = 0.0);
         LocationVectorVector locate(const std::string & input,
                                     double time_cutoff = 0.0);
+        void note_analysis(unsigned int input_pos, unsigned int tape_pos);
+        void grab_location(unsigned int input_pos, unsigned int tape_pos);
+        std::pair<SymbolNumberVector::iterator,
+                  SymbolNumberVector::iterator>
+        get_longest_matching_capture(SymbolNumber key, unsigned int input_pos);
         std::string get_profiling_info(void);
         std::string get_pattern_count_info(void);
         bool has_queued_input(unsigned int input_pos);
+        bool input_matches_at(unsigned int pos,
+                              SymbolNumberVector::iterator begin,
+                              SymbolNumberVector::iterator end);
         bool not_possible_first_symbol(SymbolNumber sym)
         {
             if (possible_first_symbols.size() == 0) {
@@ -195,10 +246,8 @@ namespace hfst_ol {
             return sym >= possible_first_symbols.size() ||
                 possible_first_symbols[sym] == 0;
         }
-        void copy_to_output(const DoubleTape & best_result);
-        void copy_to_output(SymbolNumber input, SymbolNumber output);
-        std::string stringify_output(void);
-//        LocationVector locatefy_output(void);
+        void copy_to_result(const DoubleTape & best_result);
+        void copy_to_result(SymbolNumber input, SymbolNumber output);
         static std::map<std::string, std::string> parse_hfst3_header(std::istream & f);
         void set_verbose(bool b) { verbose = b; }
         void set_locate_mode(bool b) { locate_mode = b; }
@@ -218,6 +267,29 @@ namespace hfst_ol {
             { max_context_length = max; }
         bool is_in_locate_mode(void) { return locate_mode; }
         void set_profile(bool b) { profile_mode = b; }
+        void set_weight(Weight w) { running_weight = w; }
+        void increment_weight(Weight w) { running_weight += w; }
+        Weight get_weight(void) { return running_weight; }
+        void increase_stack_depth(void) { ++stack_depth; }
+        void decrease_stack_depth(void)
+            {
+                if (stack_depth == 0) {
+                    HFST_THROW_MESSAGE(HfstException, "pmatch: negative stack depth");
+                }
+                --stack_depth;
+            }
+        void push_rtn_call(unsigned int return_index, PmatchTransducer * caller);
+        RtnStackFrame rtn_stack_top(void);
+        void rtn_stack_pop(void);
+        unsigned int get_stack_depth(void) { return stack_depth; }
+        bool candidate_found(void)
+            {
+                if (locate_mode) {
+                    return tape_locations.size() != 0;
+                } else {
+                    return best_result.size() != 0;
+                }
+            }
         bool try_recurse(void)
         {
             if (recursion_depth_left > 0) {
@@ -260,6 +332,7 @@ namespace hfst_ol {
     class PmatchTransducer
     {
     protected:
+        std::string name;
         enum ContextChecking{none, LC, NLC, RC, NRC};
 
 // Transducers have static data, ie. tables for describing the states and
@@ -269,6 +342,8 @@ namespace hfst_ol {
         struct LocalVariables
         {
             hfst::FdState<SymbolNumber> flag_state;
+
+            // Used for context checks
             char tape_step;
             size_t max_context_length_remaining;
             unsigned int context_placeholder;
@@ -276,22 +351,9 @@ namespace hfst_ol {
             bool default_symbol_trap;
             bool negative_context_success;
             bool pending_passthrough;
-            Weight running_weight;
-        };
-
-        struct RtnVariables
-        {
-            unsigned int candidate_input_pos;
-            unsigned int candidate_tape_pos;
-            unsigned int input_tape_entry;
-            unsigned int tape_entry;
-            DoubleTape best_result;
-            Weight best_weight;
-            bool candidate_found;
         };
 
         std::stack<LocalVariables> local_stack;
-        std::stack<RtnVariables> rtn_stack;
     
         std::vector<TransitionW> transition_table;
         std::vector<TransitionWIndex> index_table;
@@ -299,7 +361,6 @@ namespace hfst_ol {
         PmatchAlphabet & alphabet;
         SymbolNumber orig_symbol_count;
         PmatchContainer * container;
-        WeightedDoubleTapeVector * locations;
 
         bool is_final(TransitionTableIndex i)
         {
@@ -310,7 +371,7 @@ namespace hfst_ol {
             }
         }
 
-        bool get_weight(TransitionTableIndex i)
+        Weight get_weight(TransitionTableIndex i)
         {
             if (indexes_transition_table(i)) {
                 return transition_table[i - TRANSITION_TARGET_TABLE_START].get_weight();
@@ -332,8 +393,6 @@ namespace hfst_ol {
             }
         }
 
-        void match_like_arc(unsigned int input_pos, unsigned int tape_pos);
-
         // The mutually recursive lookup-handling functions
 
         void take_epsilons(unsigned int input_pos,
@@ -344,11 +403,6 @@ namespace hfst_ol {
                            unsigned int tape_pos,
                            TransitionTableIndex i);
   
-        void take_rtn(SymbolNumber input,
-                      unsigned int input_pos,
-                      unsigned int tape_pos,
-                      TransitionTableIndex i);
-  
         void take_flag(SymbolNumber input,
                        unsigned int input_pos,
                        unsigned int tape_pos,
@@ -390,11 +444,13 @@ namespace hfst_ol {
                          TransitionTableIndex index_table_size,
                          TransitionTableIndex transition_table_size,
                          PmatchAlphabet & alphabet,
+                         std::string name,
                          PmatchContainer * container);
 
         PmatchTransducer(std::vector<TransitionW> transition_vector,
                          std::vector<TransitionWIndex> index_vector,
                          PmatchAlphabet & alphabet,
+                         std::string name,
                          PmatchContainer * container);
 
         std::set<SymbolNumber> possible_first_symbols;
@@ -414,18 +470,11 @@ namespace hfst_ol {
         static bool is_good(TransitionTableIndex i)
         { return  i < TRANSITION_TARGET_TABLE_START; }
 
-        const DoubleTape & get_best_result(void) const
-        { return rtn_stack.top().best_result; }
-        unsigned int get_candidate_input_pos(void) const
-        { return rtn_stack.top().candidate_input_pos; }
-        Weight get_best_weight(void) const
-        { return rtn_stack.top().best_weight; }
-    
-        void match(unsigned int & input_pos, unsigned int & tape_pos);
-        void rtn_call(unsigned int & input_pos, unsigned int & tape_pos);
-        void rtn_exit(void);
-        void note_analysis(unsigned int input_pos, unsigned int tape_pos);
-        void grab_location(unsigned int input_pos, unsigned int tape_pos);
+        void match(unsigned int input_pos, unsigned int tape_pos);
+        void rtn_call(unsigned int input_pos, unsigned int tape_pos,
+                      PmatchTransducer * caller, TransitionTableIndex caller_index);
+        void rtn_return(unsigned int input_pos, unsigned int tape_pos);
+        void handle_final_state(unsigned int input_pos, unsigned int tape_pos);
         void collect_possible_first_symbols(void);
 
         friend class PmatchContainer;
diff --git a/tools/src/hfst-tokenize.cc b/libhfst/src/implementations/optimized-lookup/pmatch_tokenize.cc
similarity index 51%
copy from tools/src/hfst-tokenize.cc
copy to libhfst/src/implementations/optimized-lookup/pmatch_tokenize.cc
index 91a0075..12e8ea7 100644
--- a/tools/src/hfst-tokenize.cc
+++ b/libhfst/src/implementations/optimized-lookup/pmatch_tokenize.cc
@@ -1,139 +1,35 @@
-//! @file hfst-tokenize.cc
-//!
-//! @brief A demo of a replacement for hfst-proc using pmatch
-//!
-//! @author HFST Team
-
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, version 3 of the License.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
+// Copyright (c) 2016-2017 University of Helsinki
 //
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 3 of the License, or (at your option) any later version.
+// See the file COPYING included with this distribution for more
+// information.
 
+#include "pmatch_tokenize.h"
 
-#include <iterator>
-#include <iostream>
-#include <fstream>
-#include <iterator>
-
-#include <vector>
-#include <map>
-#include <string>
-#include <set>
+namespace hfst_ol_tokenize {
 
 using std::string;
 using std::vector;
 using std::pair;
 
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <getopt.h>
-#include <math.h>
-#include <errno.h>
-
-#include "hfst-commandline.h"
-#include "hfst-program-options.h"
-#include "hfst-tool-metadata.h"
-#include "implementations/optimized-lookup/pmatch.h"
-#include "parsers/pmatch_utils.h"
-#include "HfstExceptionDefs.h"
-#include "HfstDataTypes.h"
-#include "HfstInputStream.h"
-#include "implementations/ConvertTransducerFormat.h"
-
-using hfst::HfstTransducer;
-
-#include "inc/globals-common.h"
-#include "inc/globals-unary.h"
-
-static bool superblanks = false; // Input is apertium-style superblanks (overrides blankline_separated)
-static bool blankline_separated = true; // Input is separated by blank lines (as opposed to single newlines)
-static bool keep_newlines = false;
-static bool print_all = false;
-static bool print_weights = false;
-static bool tokenize_multichar = false;
-static string tag_separator = "+"; // + and # are hardcoded in cg-conv at least
-static string subreading_separator = "#";
-static string wtag = "W"; // TODO: cg-conv has an argument --wtag, allow changing here as well?
-static double time_cutoff = 0.0;
-static int token_number = 1;
-static int max_weight_classes = std::numeric_limits<int>::max();
-static bool dedupe = false;
-std::string tokenizer_filename;
-static hfst::ImplementationType default_format = hfst::TROPICAL_OPENFST_TYPE;
-enum OutputFormat {
-    tokenize,
-    space_separated,
-    xerox,
-    cg,
-    finnpos,
-    giellacg,
-    conllu
-};
-OutputFormat output_format = tokenize;
-
 using hfst_ol::Location;
 using hfst_ol::LocationVector;
 using hfst_ol::LocationVectorVector;
 
-void
-print_usage()
-{
-    // c.f. http://www.gnu.org/prep/standards/standards.html#g_t_002d_002dhelp
-    fprintf(message_out, "Usage: %s [--segment | --xerox | --cg | --giella-cg] [OPTIONS...] RULESET\n"
-            "perform matching/lookup on text streams\n"
-            "\n", program_name);
-    print_common_program_options(message_out);
-    fprintf(message_out,
-            "  -n, --newline            Newline as input separator (default is blank line)\n"
-            "  -a, --print-all          Print nonmatching text\n"
-            "  -w, --print-weight       Print weights\n"
-            "  -m, --tokenize-multichar Tokenize multicharacter symbols\n"
-            "                           (by default only one utf-8 character is tokenized at a time\n"
-            "                           regardless of what is present in the alphabet)\n"
-            "  -tS, --time-cutoff=S     Limit search after having used S seconds per input\n"
-            "  -lN, --weight-classes=N  Output no more than N best weight classes\n"
-            "                           (where analyses with equal weight constitute a class\n"
-            "  -u, --unique             Remove duplicate analyses\n"
-            "  -z, --segment            Segmenting / tokenization mode (default)\n"
-	    "  -i, --space-separated    Tokenization with one sentence per line, space-separated tokens\n"
-            "  -x, --xerox              Xerox output\n"
-            "  -c, --cg                 Constraint Grammar output\n"
-            "  -S, --superblanks        Ignore contents of unescaped [] (cf. apertium-destxt); flush on NUL\n"
-            "  -g, --giella-cg          CG format used in Giella infrastructe (implies -l2,\n"
-            "                           treats @PMATCH_INPUT_MARK@ as subreading separator,\n"
-            "                           expects tags to start or end with +, flush on NUL)\n"
-            "  -C  --conllu             CoNLL-U format\n"
-            "  -f, --finnpos            FinnPos output\n");
-    fprintf(message_out,
-            "Use standard streams for input and output (for now).\n"
-            "\n"
-        );
+static const string subreading_separator = "#";
+static const string wtag = "W"; // TODO: cg-conv has an argument --wtag, allow changing here as well?
 
-    print_report_bugs();
-    fprintf(message_out, "\n");
-    print_more_info();
-    fprintf(message_out, "\n");
-}
 
-void print_no_output(std::string const & input, std::ostream & outstream)
+void print_no_output(std::string const & input, std::ostream & outstream, const TokenizeSettings& s)
 {
-    if (output_format == tokenize || output_format == space_separated) {
+    if (s.output_format == tokenize || s.output_format == space_separated) {
         outstream << input;
-    } else if (output_format == xerox) {
+    } else if (s.output_format == xerox) {
         outstream << input << "\t" << input << "+?";
-    } else if (output_format == cg || output_format == giellacg) {
+    } else if (s.output_format == cg || s.output_format == giellacg) {
 	    outstream << "\"<" << input << ">\"" << std::endl << "\t\"" << input << "\" ?";
     }
 //    std::cerr << "from print_no_output\n";
@@ -151,103 +47,26 @@ void print_escaping_newlines(std::string const & str, std::ostream & outstream)
     outstream << str.substr(i, j-i);
 }
 
-void print_nonmatching_sequence(std::string const & str, std::ostream & outstream)
+void print_nonmatching_sequence(std::string const & str, std::ostream & outstream, const TokenizeSettings& s)
 {
-    if (output_format == tokenize || output_format == space_separated) {
+    if (s.output_format == tokenize || s.output_format == space_separated) {
         outstream << str;
-    } else if (output_format == xerox) {
+    } else if (s.output_format == xerox) {
         outstream << str << "\t" << str << "+?";
-    } else if (output_format == cg) {
+    } else if (s.output_format == cg) {
         outstream << "\"<" << str << ">\"" << std::endl << "\t\"" << str << "\" ?";
-    } else if (output_format == giellacg) {
+    } else if (s.output_format == giellacg) {
         outstream << ":";
         print_escaping_newlines(str, outstream);
-    } else if (output_format == conllu) {
+    } else if (s.output_format == conllu) {
         outstream << str;
-    } else if (output_format == finnpos) {
+    } else if (s.output_format == finnpos) {
         outstream << str << "\t_\t_\t_\t_";
     }
 //    std::cerr << "from print_nonmatching_sequence\n";
     outstream << "\n";
 }
 
-hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
-{
-    HfstTransducer * word_boundary = hfst::pmatch::PmatchUtilityTransducers::
-        make_latin1_whitespace_acceptor(default_format);
-    HfstTransducer * punctuation = hfst::pmatch::PmatchUtilityTransducers::
-        make_latin1_punct_acceptor(default_format);
-    word_boundary->disjunct(*punctuation);
-    HfstTransducer * others = hfst::pmatch::make_exc_list(word_boundary,
-                                                          default_format);
-    others->repeat_plus();
-    // make the default token less likely than any dictionary token
-    others->set_final_weights(std::numeric_limits<float>::max());
-    HfstTransducer * word_boundary_list = hfst::pmatch::make_list(
-        word_boundary, default_format);
-    // @BOUNDARY@ is pmatch's special input boundary marker
-    word_boundary_list->disjunct(HfstTransducer("@BOUNDARY@", default_format));
-    delete word_boundary; delete punctuation;
-    HfstTransducer * left_context = new HfstTransducer(
-        hfst::internal_epsilon, hfst::pmatch::LC_ENTRY_SYMBOL, default_format);
-    HfstTransducer * right_context = new HfstTransducer(
-        hfst::internal_epsilon, hfst::pmatch::RC_ENTRY_SYMBOL, default_format);
-    left_context->concatenate(*word_boundary_list);
-    right_context->concatenate(*word_boundary_list);
-    delete word_boundary_list;
-    HfstTransducer * left_context_exit = new HfstTransducer(
-        hfst::internal_epsilon, hfst::pmatch::LC_EXIT_SYMBOL, default_format);
-    HfstTransducer * right_context_exit = new HfstTransducer(
-        hfst::internal_epsilon, hfst::pmatch::RC_EXIT_SYMBOL, default_format);
-    left_context->concatenate(*left_context_exit);
-    right_context->concatenate(*right_context_exit);
-    delete left_context_exit; delete right_context_exit;
-    std::string dict_name = dictionary.get_name();
-    if (dict_name == "") {
-        dict_name = "unknown_pmatch_tokenized_dict";
-        dictionary.set_name(dict_name);
-    }
-    HfstTransducer dict_ins_arc(hfst::pmatch::get_Ins_transition(dict_name.c_str()), default_format);
-    // We now make the center of the tokenizer
-    others->disjunct(dict_ins_arc);
-    // And combine it with the context conditions
-    left_context->concatenate(*others);
-    left_context->concatenate(*right_context);
-    delete others; delete right_context;
-    // Because there are context conditions we need delimiter markers
-    HfstTransducer * tokenizer = hfst::pmatch::add_pmatch_delimiters(left_context);
-    tokenizer->set_name("TOP");
-    tokenizer->minimize();
-    // Convert the dictionary to olw if it wasn't already
-    dictionary.convert(hfst::HFST_OLW_TYPE);
-    // Get the alphabets
-    std::set<std::string> dict_syms = dictionary.get_alphabet();
-    std::set<std::string> tokenizer_syms = tokenizer->get_alphabet();
-    std::vector<std::string> tokenizer_minus_dict;
-    // What to add to the dictionary
-    std::set_difference(tokenizer_syms.begin(), tokenizer_syms.end(),
-                        dict_syms.begin(), dict_syms.end(),
-                        std::inserter(tokenizer_minus_dict, tokenizer_minus_dict.begin()));
-    for (std::vector<std::string>::const_iterator it = tokenizer_minus_dict.begin();
-         it != tokenizer_minus_dict.end(); ++it) {
-        dictionary.insert_to_alphabet(*it);
-    }
-    hfst::HfstBasicTransducer * tokenizer_basic = hfst::implementations::ConversionFunctions::
-        hfst_transducer_to_hfst_basic_transducer(*tokenizer);
-    hfst_ol::Transducer * tokenizer_ol = hfst::implementations::ConversionFunctions::
-        hfst_basic_transducer_to_hfst_ol(tokenizer_basic,
-                                         true, // weighted
-                                         "", // no special options
-                                         &dictionary); // harmonize with the dictionary
-    delete tokenizer_basic;
-    hfst_ol::PmatchContainer retval(tokenizer_ol);
-    hfst_ol::Transducer * dict_backend = hfst::implementations::ConversionFunctions::
-        hfst_transducer_to_hfst_ol(&dictionary);
-    retval.add_rtn(dict_backend, dict_name);
-    delete tokenizer_ol;
-    return retval;
-}
-
 bool location_compare(const Location& lhs, const Location& rhs) {
     if (lhs.weight == rhs.weight) {
         if(lhs.tag == rhs.tag) {
@@ -272,11 +91,11 @@ bool location_compare(const Location& lhs, const Location& rhs) {
     }
 };
 
-/**
- * Keep only the max_weight_classes best weight classes
- */
-const LocationVector dedupe_locations(LocationVector const & locations) {
-    if(!dedupe) {
+
+
+
+const LocationVector dedupe_locations(LocationVector const & locations, const TokenizeSettings& s) {
+    if(!s.dedupe) {
         return locations;
     }
     std::set<Location, bool(*)(const Location& lhs, const Location& rhs)> ls(&location_compare);
@@ -288,9 +107,9 @@ const LocationVector dedupe_locations(LocationVector const & locations) {
 /**
  * Keep only the max_weight_classes best weight classes
  */
-const LocationVector keep_n_best_weight(LocationVector const & locations)
+const LocationVector keep_n_best_weight(LocationVector const & locations, const TokenizeSettings& s)
 {
-    if(locations.size() <= max_weight_classes) {
+    if(locations.size() <= s.max_weight_classes) {
         // We know we won't trim anything, no need to copy the vector:
         return locations;
     }
@@ -314,7 +133,7 @@ const LocationVector keep_n_best_weight(LocationVector const & locations)
             last_weight_class = current_weight;
             ++classes_found;
         }
-        if (classes_found > max_weight_classes)
+        if (classes_found > s.max_weight_classes)
         {
             break;
         }
@@ -326,19 +145,36 @@ const LocationVector keep_n_best_weight(LocationVector const & locations)
 }
 
 /**
- * Return empty string if it wasn't a tag, otherwise the tag without the initial/final +
+ * Return the size in bytes of the first complete UTF-8 codepoint in c,
+ * or 0 if invalid.
  */
-const string as_cg_tag(const string & str) {
-    size_t len = str.size();
-    if(len > 1) {
-        if (str.at(0) == '+') {
-            return str.substr(1);
-        }
-        else if(str.at(len - 1) == '+') {
-            return str.substr(0, len - 1);
-        }
+size_t u8_first_codepoint_size(const unsigned char* c) {
+    if (*c <= 127) {
+        return 1;
+    }
+    else if ( (*c & (128 + 64 + 32 + 16)) == (128 + 64 + 32 + 16) ) {
+        return 4;
+    }
+    else if ( (*c & (128 + 64 + 32 )) == (128 + 64 + 32) ) {
+        return 3;
+    }
+    else if ( (*c & (128 + 64 )) == (128 + 64)) {
+        return 2;
+    }
+    else {
+        return 0;
     }
-    return "";
+}
+
+/**
+ * We define tags (non-lemmas) as being exactly the Multichar_symbols.
+ * Since non-Multichar_symbols may still be multi*byte*, we check that
+ * the symbol is strictly longer than the size of the first
+ * possibly-multi-byte codepoint.
+ */
+bool is_cg_tag(const string & str) {
+    // Note: invalid codepoints are also treated as tags;  ¯\_(ツ)_/¯
+    return str.size() > u8_first_codepoint_size((const unsigned char*)str.c_str());
 }
 
 void print_cg_subreading(size_t const & indent,
@@ -347,46 +183,36 @@ void print_cg_subreading(size_t const & indent,
                          hfst_ol::Weight const & weight,
                          hfst::StringVector::const_iterator & in_beg,
                          hfst::StringVector::const_iterator & in_end,
-                         std::ostream & outstream)
+                         std::ostream & outstream,
+                         const TokenizeSettings& s)
 {
     outstream << string(indent, '\t');
     bool in_lemma = false;
-    bool want_spc = false;
     for(hfst::StringVector::const_iterator it = out_beg;
         it != out_end; ++it) {
         if(it->compare("@PMATCH_BACKTRACK@") == 0) {
             continue;
         }
-        const string & tag = as_cg_tag(*it);
+        bool is_tag = is_cg_tag(*it);
         if(in_lemma) {
-            if(tag.empty()) {
-                outstream << (*it);
-            }
-            else {
+            if(is_tag) {
                 in_lemma = false;
-                outstream << "\" " << tag;
-                want_spc = true;
+                outstream << "\"";
             }
         }
         else {
-            if(want_spc) {
-                outstream << " ";
-            }
-            if(tag.empty()) {
+            if(!is_tag) {
                 in_lemma = true;
-                outstream << "\"" << (*it);
-            }
-            else {
-                outstream << tag;
-                want_spc = true;
+                outstream << "\"";
             }
         }
+        outstream << (*it);
     }
     if(in_lemma) {
         outstream << "\"";
     }
 
-    if (print_weights) {
+    if (s.print_weights) {
         outstream << " <" << wtag << ":" << weight << ">";
     }
     if (in_beg != in_end) {
@@ -403,7 +229,8 @@ pair<SplitPoints, size_t>
 print_reading_giellacg(const Location *loc,
                        size_t indent,
                        const bool always_wftag,
-                       std::ostream & outstream)
+                       std::ostream & outstream,
+                       const TokenizeSettings& s)
 {
     SplitPoints bt_its;
     if(loc->output.empty()) {
@@ -461,7 +288,8 @@ print_reading_giellacg(const Location *loc,
                             loc->weight,
                             in_beg,
                             in_end,
-                            outstream);
+                            outstream,
+                            s);
         if(out_beg == loc->output_symbol_strings.begin()) {
             break;
         }
@@ -511,9 +339,10 @@ const hfst::StringVector split_at(const hfst::StringVector & syms,
  * full string.
  */
 const LocationVector locate_fullmatch(hfst_ol::PmatchContainer & container,
-                                      string & form)
+                                      string & form,
+                                      const TokenizeSettings& s)
 {
-    LocationVectorVector sublocs = container.locate(form, time_cutoff);
+    LocationVectorVector sublocs = container.locate(form, s.time_cutoff);
     LocationVector loc_filtered;
     // TODO: Worth noticing about? Is this as safe as checking that input.length != form.length?
     // if(sublocs.size() != 1) {
@@ -527,7 +356,7 @@ const LocationVector locate_fullmatch(hfst_ol::PmatchContainer & container,
             || it->at(0).input.length() != form.length()) {
             continue;
         }
-        LocationVector loc = keep_n_best_weight(dedupe_locations(*it));
+        LocationVector loc = keep_n_best_weight(dedupe_locations(*it, s), s);
         for (LocationVector::const_iterator loc_it = loc.begin();
              loc_it != loc.end(); ++loc_it) {
             if(!loc_it->output.empty()
@@ -542,7 +371,8 @@ const LocationVector locate_fullmatch(hfst_ol::PmatchContainer & container,
 
 void print_location_vector_giellacg(hfst_ol::PmatchContainer & container,
                                     LocationVector const & locations,
-                                    std::ostream & outstream)
+                                    std::ostream & outstream,
+                                    const TokenizeSettings& s)
 {
     outstream << "\"<" << locations.at(0).input << ">\"" << std::endl;
     if(locations.size() == 1 && locations.at(0).output.empty()) {
@@ -554,7 +384,7 @@ void print_location_vector_giellacg(hfst_ol::PmatchContainer & container,
     std::set<SplitPoints> backtrack;
     for (LocationVector::const_iterator loc_it = locations.begin();
          loc_it != locations.end(); ++loc_it) {
-        SplitPoints bt_points = print_reading_giellacg(&(*loc_it), 1, false, outstream).first;
+        SplitPoints bt_points = print_reading_giellacg(&(*loc_it), 1, false, outstream, s).first;
         if(!bt_points.empty()) {
             backtrack.insert(bt_points);
         }
@@ -579,8 +409,8 @@ void print_location_vector_giellacg(hfst_ol::PmatchContainer & container,
             const size_t first = it->find_first_not_of(' ');
             const size_t last = it->find_last_not_of(' ') + 1;
             string form = it->substr(first, last-first);
-            LocationVector loc = locate_fullmatch(container, form);
-            if(loc.size() == 0 && verbose) {
+            LocationVector loc = locate_fullmatch(container, form, s);
+            if(loc.size() == 0 && s.verbose) {
                 std::cerr << "Warning: The analysis of \"<" << locations.at(0).input << ">\" has backtracking around the substring \"<" << form << ">\", but that substring has no analyses." << std::endl;
                 // but push it anyway, since we want exactly one subvector per splitpoint
             }
@@ -624,7 +454,7 @@ void print_location_vector_giellacg(hfst_ol::PmatchContainer & container,
             out.at(depth).clear();
             out.at(depth).str(string());
             // (ignore splitpoints of splitpoints)
-            const size_t new_indent = print_reading_giellacg(&loc, indent, true, out.at(depth)).second;
+            const size_t new_indent = print_reading_giellacg(&loc, indent, true, out.at(depth), s).second;
             if(depth == bottom) {
                 for(vector<std::ostringstream>::const_iterator it = out.begin(); it != out.end(); ++it) {
                     outstream << it->str();
@@ -710,29 +540,32 @@ std::string empty_to_underscore(std::string to_test)
     return to_test;
 }
 
+
 void print_location_vector(hfst_ol::PmatchContainer & container,
                            LocationVector const & locations,
-                           std::ostream & outstream)
+                           std::ostream & outstream,
+                           int token_number,
+                           const TokenizeSettings& s)
 {
-    if (output_format == tokenize && locations.size() != 0) {
+    if (s.output_format == tokenize && locations.size() != 0) {
         outstream << locations.at(0).input;
-        if (print_weights) {
+        if (s.print_weights) {
             outstream << "\t" << locations.at(0).weight;
         }
         outstream << std::endl;
         if (locations.at(0).tag == "<Boundary=Sentence>") {
             outstream << std::endl;
         }
-    } else if (output_format == space_separated && locations.size() != 0) {
+    } else if (s.output_format == space_separated && locations.size() != 0) {
 	outstream << locations.at(0).input;
-        if (print_weights) {
+        if (s.print_weights) {
             outstream << "\t" << locations.at(0).weight;
         }
         outstream << " ";
         if (locations.at(0).tag == "<Boundary=Sentence>") {
             outstream << std::endl;
         }
-    } else if (output_format == cg && locations.size() != 0) {
+    } else if (s.output_format == cg && locations.size() != 0) {
         // Print the cg cohort header
         outstream << "\"<" << locations.at(0).input << ">\"" << std::endl;
         for (LocationVector::const_iterator loc_it = locations.begin();
@@ -747,25 +580,36 @@ void print_location_vector(hfst_ol::PmatchContainer & container,
             } else {
                 outstream << "\t" << loc_it->output;
             }
-            if (print_weights) {
+            if (s.print_weights) {
                 outstream << "\t" << loc_it->weight;
             }
             outstream << std::endl;
         }
         outstream << std::endl;
-    } else if (output_format == giellacg && locations.size() != 0) {
-        print_location_vector_giellacg(container, locations, outstream);
-    } else if (output_format == xerox) {
+    } else if (s.output_format == giellacg && locations.size() != 0) {
+        print_location_vector_giellacg(container, locations, outstream, s);
+    } else if (s.output_format == xerox) {
+        float best_weight = std::numeric_limits<float>::max();
+        if (s.beam >= 0.0) {
+            for (LocationVector::const_iterator loc_it = locations.begin();
+                 loc_it != locations.end(); ++loc_it) {
+                if (best_weight > loc_it->weight) {
+                    best_weight = loc_it->weight;
+                }
+            }
+        }
         for (LocationVector::const_iterator loc_it = locations.begin();
              loc_it != locations.end(); ++loc_it) {
-            outstream << loc_it->input << "\t" << loc_it->output;
-            if (print_weights) {
-                outstream << "\t" << loc_it->weight;
+            if (s.beam < 0.0 || loc_it->weight <= best_weight + s.beam) {
+                outstream << loc_it->input << "\t" << loc_it->output;
+                if (s.print_weights) {
+                    outstream << "\t" << loc_it->weight;
+                }
+                outstream << std::endl;
             }
-            outstream << std::endl;
         }
         outstream << std::endl;
-    } else if (output_format == conllu) {
+    } else if (s.output_format == conllu) {
         hfst_ol::Weight lowest_weight = hfst_ol::INFINITE_WEIGHT;
         hfst_ol::Location best_location;
         for (LocationVector::const_iterator loc_it = locations.begin();
@@ -787,11 +631,11 @@ void print_location_vector(hfst_ol::PmatchContainer & container,
                   << "\t" << "_" // DEPREL
                   << "\t" << "_"; // DEPS
         outstream << "\t" << empty_to_underscore(best_location.output); // MISC
-                    if (print_weights) {
+                    if (s.print_weights) {
                 outstream << "\t" << best_location.weight;
             }
         outstream << std::endl;
-    } else if (output_format == finnpos) {
+    } else if (s.output_format == finnpos) {
         std::set<std::string> tags;
         std::set<std::string> lemmas;
             for (LocationVector::const_iterator loc_it = locations.begin();
@@ -846,359 +690,48 @@ void print_location_vector(hfst_ol::PmatchContainer & container,
 
 void match_and_print(hfst_ol::PmatchContainer & container,
                      std::ostream & outstream,
-                     const string & input_text)
+                     const string & input_text,
+                     const TokenizeSettings& s)
 {
-    LocationVectorVector locations = container.locate(input_text, time_cutoff);
-    if (locations.size() == 0 && print_all) {
-        print_no_output(input_text, outstream);
+    LocationVectorVector locations = container.locate(input_text, s.time_cutoff);
+    if (locations.size() == 0 && s.print_all) {
+        print_no_output(input_text, outstream, s);
     }
-    token_number = 1;
+    int token_number = 1;
     for(LocationVectorVector::const_iterator it = locations.begin();
         it != locations.end(); ++it) {
         if ((it->size() == 1 && it->at(0).output.compare("@_NONMATCHING_@") == 0)) {
-            if (print_all) {
-                print_nonmatching_sequence(it->at(0).input, outstream);
+            if (s.print_all) {
+                print_nonmatching_sequence(it->at(0).input, outstream, s);
             }
             continue;
             // All nonmatching cases have been handled
         }
         print_location_vector(container,
-                              keep_n_best_weight(dedupe_locations(*it)),
-                              outstream);
+                              keep_n_best_weight(dedupe_locations(*it, s), s),
+                              outstream,
+                              token_number,
+                              s);
         ++token_number;
     }
-    if (output_format == finnpos) {
+    if (s.output_format == finnpos) {
         outstream << std::endl;
     }
 }
 
-// TODO: lambda this when C++11 available everywhere
-inline void process_input_0delim_print(hfst_ol::PmatchContainer & container,
-                                       std::ostream & outstream,
-                                       std::ostringstream& cur)
-{
-    string input_text(cur.str());
-    if(!input_text.empty()) {
-        match_and_print(container, outstream, input_text);
-    }
-    cur.clear();
-    cur.str(string());
-}
-
-template<bool do_superblank>
-int process_input_0delim(hfst_ol::PmatchContainer & container,
-                         std::ostream & outstream)
-{
-    char * line = NULL;
-    size_t bufsize = 0;
-    bool in_blank = false;
-    std::ostringstream cur;
-    ssize_t len = -1;
-    while ((len = hfst_getdelim(&line, &bufsize, '\0', inputfile)) > 0) {
-        bool escaped = false; // beginning of line is necessarily unescaped
-        for(size_t i = 0; i < len; ++i) {
-            if(escaped) {
-                cur << line[i];
-                escaped = false;
-                continue;
-            }
-            else if(do_superblank && !in_blank && line[i] == '[') {
-                process_input_0delim_print(container, outstream, cur);
-                cur << line[i];
-                in_blank = true;
-            }
-            else if(do_superblank && in_blank && line[i] == ']') {
-                cur << line[i];
-                if(i+1 < len && line[i+1] == '[') {
-                    // Join consecutive superblanks
-                    ++i;
-                    cur << line[i];
-                }
-                else {
-                    in_blank = false;
-                    print_nonmatching_sequence(cur.str(), outstream);
-                    cur.clear();
-                    cur.str(string());
-                }
-            }
-            else if(!in_blank && line[i] == '\n') {
-                cur << line[i];
-                process_input_0delim_print(container, outstream, cur);
-            }
-            else if(line[i] == '\0') {
-                process_input_0delim_print(container, outstream, cur);
-                outstream << "<STREAMCMD:FLUSH>" << std::endl; // CG format uses this instead of \0
-                outstream.flush();
-                if(outstream.bad()) {
-                    std::cerr << "hfst-tokenize: Could not flush file" << std::endl;
-                }
-            }
-            else {
-                cur << line[i];
-            }
-            escaped = (line[i] == '\\');
-        }
-        free(line);
-        line = NULL;
-        if(std::feof(inputfile)) {
-            break;
-        }
-    }
-    if(in_blank) {
-        print_nonmatching_sequence(cur.str(), outstream);
-    }
-    else {
-        process_input_0delim_print(container, outstream, cur);
-    }
-    return EXIT_SUCCESS;
-}
-
-inline void maybe_erase_newline(string& input_text)
-{
-    if(!keep_newlines && input_text.size() > 0 && input_text.at(input_text.size() - 1) == '\n') {
-        // Remove final newline
-        input_text.erase(input_text.size() -1, 1);
-    }
-}
-
-int process_input(hfst_ol::PmatchContainer & container,
-                  std::ostream & outstream)
+void process_input(hfst_ol::PmatchContainer & container,
+                   std::istream& instream,
+                   std::ostream& outstream,
+                   const TokenizeSettings& s)
 {
-    if(output_format == giellacg || superblanks) {
-        if(superblanks) {
-            return process_input_0delim<true>(container, outstream);
-        }
-        else {
-            return process_input_0delim<false>(container, outstream);
-        }
-    }
-    string input_text;
-    char * line = NULL;
-    size_t bufsize = 0;
-    if(blankline_separated) {
-        while (hfst_getline(&line, &bufsize, inputfile) > 0) {
-            if (line[0] == '\n') {
-                maybe_erase_newline(input_text);
-                match_and_print(container, outstream, input_text);
-                input_text.clear();
-            } else {
-                input_text.append(line);
-            }
-            free(line);
-            line = NULL;
-        }
-        if (!input_text.empty()) {
-            maybe_erase_newline(input_text);
-            match_and_print(container, outstream, input_text);
-        }
-    }
-    else {
-        // newline or non-separated
-        while (hfst_getline(&line, &bufsize, inputfile) > 0) {
-            input_text = line;
-            maybe_erase_newline(input_text);
-            match_and_print(container, outstream, input_text);
-            free(line);
-            line = NULL;
-        }
-    }
-
-    return EXIT_SUCCESS;
-}
-
-int parse_options(int argc, char** argv)
-{
-    extend_options_getenv(&argc, &argv);
-    // use of this function requires options are settable on global scope
-    while (true)
-    {
-        static const struct option long_options[] =
-            {
-                HFST_GETOPT_COMMON_LONG,
-                {"newline", no_argument, 0, 'n'},
-                {"keep-newline", no_argument, 0, 'k'},
-                {"print-all", no_argument, 0, 'a'},
-                {"print-weights", no_argument, 0, 'w'},
-                {"tokenize-multichar", no_argument, 0, 'm'},
-                {"time-cutoff", required_argument, 0, 't'},
-                {"weight-classes", required_argument, 0, 'l'},
-                {"unique", required_argument, 0, 'u'},
-                {"segment", no_argument, 0, 'z'},
-		{"space-separated", no_argument, 0, 'd'},
-                {"xerox", no_argument, 0, 'x'},
-                {"cg", no_argument, 0, 'c'},
-                {"superblanks", no_argument, 0, 'S'},
-                {"giella-cg", no_argument, 0, 'g'},
-                {"gtd", no_argument, 0, 'g'},
-                {"conllu", no_argument, 0, 'C'},
-                {"finnpos", no_argument, 0, 'f'},
-                {0,0,0,0}
-            };
-        int option_index = 0;
-        int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT "nkawmut:l:zixcSgCf",
-                             long_options, &option_index);
-        if (-1 == c)
-        {
-            break;
-        }
-
-
-        switch (c)
-        {
-#include "inc/getopt-cases-common.h"
-        case 'k':
-            keep_newlines = true;
-            blankline_separated = false;
-            break;
-        case 'n':
-            blankline_separated = false;
-            break;
-        case 'a':
-            print_all = true;
-            break;
-        case 'w':
-            print_weights = true;
-            break;
-        case 'm':
-            tokenize_multichar = true;
-            break;
-        case 't':
-            time_cutoff = atof(optarg);
-            if (time_cutoff < 0.0)
-            {
-                std::cerr << "Invalid argument for --time-cutoff\n";
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'u':
-            dedupe = true;
-            break;
-        case 'l':
-            max_weight_classes = atoi(optarg);
-            if (max_weight_classes < 1)
-            {
-                std::cerr << "Invalid or no argument --weight-classes count\n";
-                return EXIT_FAILURE;
-            }
-            break;
-        case 'z':
-            output_format = tokenize;
-            break;
-        case 'i':
-            output_format = space_separated;
-            break;
-        case 'x':
-            output_format = xerox;
-            break;
-        case 'c':
-            output_format = cg;
-            break;
-        case 'C':
-            output_format = conllu;
-            break;
-        case 'S':
-            superblanks = true;
-            break;
-        case 'g':
-            output_format = giellacg;
-            print_weights = true;
-            print_all = true;
-            dedupe = true;
-            if(max_weight_classes == std::numeric_limits<int>::max()) {
-                max_weight_classes = 2;
-            }
-            break;
-        case 'f':
-            output_format = finnpos;
-            break;
-#include "inc/getopt-cases-error.h"
+    container.set_single_codepoint_tokenization(!s.tokenize_multichar);
+    size_t bufsize = 4096;
+    for(char line[bufsize]; instream.getline(line, bufsize); ) {
+        string input_text(line);
+        if(!input_text.empty()) {
+            match_and_print(container, outstream, input_text, s);
         }
-
-
-
     }
-
-//            if (!inputNamed)
-//        {
-//            inputfile = stdin;
-//            inputfilename = hfst_strdup("<stdin>");
-//        }
-
-        // no more options, we should now be at the input filename
-        if ( (optind + 1) < argc)
-        {
-            std::cerr << "More than one input file given\n";
-            return EXIT_FAILURE;
-        }
-        else if ( (optind + 1) == argc)
-        {
-            tokenizer_filename = argv[(optind)];
-            return EXIT_CONTINUE;
-        }
-        else
-        {
-            std::cerr << "No input file given\n";
-            return EXIT_FAILURE;
-        }
-
-
-#include "inc/check-params-common.h"
-
-
-
-    return EXIT_FAILURE;
-}
-
-bool first_transducer_is_called_TOP(const HfstTransducer & dictionary)
-{
-    return dictionary.get_name() == "TOP";
 }
 
-int main(int argc, char ** argv)
-{
-    hfst_set_program_name(argv[0], "0.1", "HfstTokenize");
-    hfst_setlocale();
-    int retval = parse_options(argc, argv);
-    if (retval != EXIT_CONTINUE) {
-        return retval;
-    }
-    std::ifstream instream(tokenizer_filename.c_str(),
-                           std::ifstream::binary);
-    if (!instream.good()) {
-        std::cerr << "Could not open file " << tokenizer_filename << std::endl;
-        return EXIT_FAILURE;
-    }
-    try {
-        hfst::HfstInputStream is(tokenizer_filename);
-        HfstTransducer dictionary(is);
-        if (first_transducer_is_called_TOP(dictionary)) {
-            instream.seekg(0);
-            instream.clear();
-            hfst_ol::PmatchContainer container(instream);
-            container.set_verbose(verbose);
-            container.set_single_codepoint_tokenization(!tokenize_multichar);
-            return process_input(container, std::cout);
-        } else {
-            instream.close();
-            hfst_ol::PmatchContainer container = make_naive_tokenizer(dictionary);
-            container.set_verbose(verbose);
-            container.set_single_codepoint_tokenization(!tokenize_multichar);
-            return process_input(container, std::cout);
-        }
-    } catch(HfstException & e) {
-        std::cerr << "The archive in " << tokenizer_filename <<
-            " doesn't look right.\nDid you make it with hfst-pmatch2fst"
-            " or make sure it's in weighted optimized-lookup format?\n"
-            "Exception thrown:\n" << e.what() << std::endl;
-        return 1;
-    }
-
-//     if (outfile != stdout) {
-//         std::filebuf fb;
-// fb.open(outfilename, std::ios::out);
-// std::ostream outstream(&fb);
-// return process_input(container, outstream);
-// fb.close();
-//     } else {
-
 }
diff --git a/libhfst/src/implementations/optimized-lookup/pmatch_tokenize.h b/libhfst/src/implementations/optimized-lookup/pmatch_tokenize.h
new file mode 100644
index 0000000..6c681ce
--- /dev/null
+++ b/libhfst/src/implementations/optimized-lookup/pmatch_tokenize.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2016-2017 University of Helsinki
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 3 of the License, or (at your option) any later version.
+// See the file COPYING included with this distribution for more
+// information.
+#ifndef _HFST_OL_TRANSDUCER_PMATCH_TOKENIZE_H_
+#define _HFST_OL_TRANSDUCER_PMATCH_TOKENIZE_H_
+
+#include <iostream>
+#include <iterator>
+
+#include "pmatch.h"
+
+namespace hfst_ol_tokenize {
+
+enum OutputFormat {
+    tokenize,
+    space_separated,
+    xerox,
+    cg,
+    finnpos,
+    giellacg,
+    conllu
+};
+
+struct TokenizeSettings {
+        OutputFormat output_format = tokenize;
+        int max_weight_classes = std::numeric_limits<int>::max();
+        bool dedupe = false;
+        bool print_weights = false;
+        bool print_all = false;
+        double time_cutoff = 0.0;
+        bool verbose = true;
+        float beam = -1.0;
+        bool tokenize_multichar = false;
+};
+
+void print_nonmatching_sequence(std::string const & str, std::ostream & outstream, const TokenizeSettings& s);
+
+void match_and_print(hfst_ol::PmatchContainer & container,
+                     std::ostream & outstream,
+                     const string & input_text,
+                     const TokenizeSettings& s);
+
+void process_input(hfst_ol::PmatchContainer & container,
+                   std::istream& instream,
+                   std::ostream& outstream,
+                   const TokenizeSettings& s);
+
+}
+
+
+#endif //_HFST_OL_TRANSDUCER_PMATCH_TOKENIZE_H_
diff --git a/libhfst/src/implementations/optimized-lookup/transducer.cc b/libhfst/src/implementations/optimized-lookup/transducer.cc
index f87db43..0538597 100644
--- a/libhfst/src/implementations/optimized-lookup/transducer.cc
+++ b/libhfst/src/implementations/optimized-lookup/transducer.cc
@@ -409,13 +409,14 @@ void Transducer::try_epsilon_transitions(unsigned int input_pos,
         SymbolNumber output = tables->get_transition_output(i);
         TransitionTableIndex target = tables->get_transition_target(i);
         Weight weight = tables->get_weight(i);
+        Weight old_weight = current_weight;
         if (input == 0) // epsilon
         {
             output_tape.write(output_pos, input, output);
             current_weight += weight;
             get_analyses(input_pos, output_pos + 1, target);
             found_transition = true;
-            current_weight -= weight;
+            current_weight = old_weight;
             ++i;
         } else if (alphabet->is_flag_diacritic(input)) {
             FlagDiacriticState flags = flag_state.get_values();
@@ -435,7 +436,7 @@ void Transducer::try_epsilon_transitions(unsigned int input_pos,
                 current_weight += weight;
                 get_analyses(input_pos, output_pos + 1, target);
                 found_transition = true;
-                current_weight -= weight;
+                current_weight = old_weight;
                 traversal_states.erase(flag_reachable);
             }
             flag_state.assign_values(flags);
@@ -470,6 +471,7 @@ void Transducer::find_transitions(SymbolNumber input,
     {
         if (tables->get_transition_input(i) == input)
         {
+            Weight old_weight = current_weight;
             // We're not going to find an epsilon / flag loop
             traversal_states.clear();
             SymbolNumber output = tables->get_transition_output(i);
@@ -485,7 +487,7 @@ void Transducer::find_transitions(SymbolNumber input,
             get_analyses(input_pos,
                          output_pos + 1,
                          tables->get_transition_target(i));
-            current_weight -= tables->get_weight(i);
+            current_weight = old_weight;
             found_transition = true;
         }
         else
@@ -545,9 +547,10 @@ void Transducer::get_analyses(unsigned int input_pos,
             if (max_lookups < 0 || (ssize_t)lookup_paths->size() < max_lookups) {
                 output_tape.write(output_pos, NO_SYMBOL_NUMBER, NO_SYMBOL_NUMBER);
                 if (tables->get_transition_finality(i)) {
+                    Weight old_weight = current_weight;
                     current_weight += tables->get_weight(i);
                     note_analysis();
-                    current_weight -= tables->get_weight(i);
+                    current_weight = old_weight;
                 }
             }
         }
@@ -594,9 +597,10 @@ void Transducer::get_analyses(unsigned int input_pos,
             if (max_lookups < 0 || (ssize_t)lookup_paths->size() < max_lookups) {
                 output_tape.write(output_pos, NO_SYMBOL_NUMBER, NO_SYMBOL_NUMBER);
                 if (tables->get_index_finality(i)) {
+                    Weight old_weight = current_weight;
                     current_weight += tables->get_final_weight(i);
                     note_analysis();
-                    current_weight -= tables->get_final_weight(i);
+                    current_weight = old_weight;
                 }
             }
         }
diff --git a/libhfst/src/implementations/optimized-lookup/transducer.h b/libhfst/src/implementations/optimized-lookup/transducer.h
index b247a6d..addb52e 100644
--- a/libhfst/src/implementations/optimized-lookup/transducer.h
+++ b/libhfst/src/implementations/optimized-lookup/transducer.h
@@ -834,6 +834,30 @@ struct DoubleTape: public std::vector<SymbolPair>
             this->operator[](pos) = SymbolPair(in, out);
         }
 
+    void write(unsigned int pos, std::vector<SymbolNumber> & vec)
+        {
+            while (pos + vec.size() >= this->size()) {
+                this->push_back(SymbolPair());
+            }
+            for (size_t i = 0; i < vec.size(); ++i) {
+                this->operator[](pos + i) = SymbolPair(vec[i], vec[i]);
+            }
+        }
+
+    void write(unsigned int pos, std::pair<SymbolNumberVector::iterator,
+               SymbolNumberVector::iterator> start_and_end)
+        {
+            size_t size = start_and_end.second - start_and_end.first;
+            while (pos + size >= this->size()) {
+                this->push_back(SymbolPair());
+            }
+            for (size_t i = 0; i < size; ++i) {
+                this->operator[](pos + i) =
+                    SymbolPair(*(start_and_end.first + i),
+                               *(start_and_end.first + i));
+            }
+        }
+
     DoubleTape extract_slice(unsigned int start, unsigned int stop)
         {
             DoubleTape retval;
diff --git a/libhfst/src/parsers/PmatchCompiler.cc b/libhfst/src/parsers/PmatchCompiler.cc
index 045eba0..bd68bb8 100644
--- a/libhfst/src/parsers/PmatchCompiler.cc
+++ b/libhfst/src/parsers/PmatchCompiler.cc
@@ -45,7 +45,8 @@ std::map<std::string, HfstTransducer*>
 PmatchCompiler::compile(const std::string& pmatch)
 {
     return hfst::pmatch::compile(pmatch, definitions_, format_,
-                                 verbose, flatten, includedir);
+                                 verbose, flatten, include_cosine_distances,
+                                 includedir);
 }
 
 void PmatchCompiler::set_include_path(std::string path)
diff --git a/libhfst/src/parsers/PmatchCompiler.h b/libhfst/src/parsers/PmatchCompiler.h
index df5824d..f55ddfd 100644
--- a/libhfst/src/parsers/PmatchCompiler.h
+++ b/libhfst/src/parsers/PmatchCompiler.h
@@ -40,6 +40,7 @@ class PmatchCompiler
 private:
     bool flatten;
     bool verbose;
+    bool include_cosine_distances;
     std::string includedir;
   public:
   //! @brief Construct compiler for unknown format transducers.
@@ -49,6 +50,8 @@ private:
 
   void set_flatten(bool val) { flatten = val; }
   void set_verbose(bool val) { verbose = val; }
+  void set_include_cosine_distances(bool val)
+        { include_cosine_distances = val; }
 
   //! @brief Add a definition macro.
   //!        Compilers will replace arcs labeled @a name, with the transducer
diff --git a/libhfst/src/parsers/SfstAlphabet.h b/libhfst/src/parsers/SfstAlphabet.h
index 0434070..855244f 100644
--- a/libhfst/src/parsers/SfstAlphabet.h
+++ b/libhfst/src/parsers/SfstAlphabet.h
@@ -5,7 +5,18 @@
 #  include <config.h>
 #endif
 
+#ifdef INCLUDE_TR1_UNORDERED_MAP_AND_SET
+#include <tr1/unordered_map>
+#else
 #include <unordered_map>
+#endif
+
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
+using std::tr1::unordered_map;
+#else
+using std::unordered_map;
+#endif
+
 #include <set>
 #include <vector>
 #include <string.h>
@@ -23,7 +34,7 @@ namespace hfst {
     public:
       typedef std::pair<unsigned int,unsigned int> NumberPair;
       // used to map the codes back to the symbols
-      typedef std::unordered_map<unsigned int, char*> CharMap;
+      typedef unordered_map<unsigned int, char*> CharMap;
 
     private:
       // string comparison operators needed ???
@@ -34,7 +45,8 @@ namespace hfst {
       };
       
       // used to map the symbols to their codes
-      typedef std::unordered_map<const char*, unsigned int> SymbolMap;
+      typedef unordered_map<const char*, unsigned int> SymbolMap;
+
       // set of symbol pairs
       typedef std::set<NumberPair> NumberPairSet;
       
diff --git a/libhfst/src/parsers/SfstBasic.cc b/libhfst/src/parsers/SfstBasic.cc
index d7147f8..9631dc6 100644
--- a/libhfst/src/parsers/SfstBasic.cc
+++ b/libhfst/src/parsers/SfstBasic.cc
@@ -21,7 +21,7 @@
     char* pStringCopy = (char*)malloc(strlen(pString) + 1);
     if (pStringCopy == NULL) {
       fprintf(stderr, "\nError: out of memory (malloc failed)\naborted.\n");
-      throw HfstException();
+      HFST_THROW(HfstException);
     }
     strcpy(pStringCopy, pString);
     return pStringCopy;
diff --git a/libhfst/src/parsers/SfstCompiler.cc b/libhfst/src/parsers/SfstCompiler.cc
index 06affd7..233b529 100644
--- a/libhfst/src/parsers/SfstCompiler.cc
+++ b/libhfst/src/parsers/SfstCompiler.cc
@@ -105,7 +105,7 @@ namespace hfst
     fprintf(stderr,
         "ERROR: The wildcard symbol '.'"
         " requires the definition of an alphabet");
-    throw HfstException();
+    HFST_THROW(HfstException);
       }
       
       // one of the ranges was '.'
@@ -168,12 +168,12 @@ namespace hfst
 
   void SfstCompiler::error( const char *message ) {
     std::cerr << "\nError: " << message << "\naborted.\n";
-    throw HfstException();
+    HFST_THROW(HfstException);
   }
 
   void SfstCompiler::error2( const char *message, char *input ) {
     std::cerr << "\nError: " << message << ": " << input << "\naborted.\n";
-    throw HfstException();
+    HFST_THROW(HfstException);
   }
   
   Character SfstCompiler::symbol_code( char *symbol )
@@ -279,7 +279,7 @@ namespace hfst
     VarMap::iterator it=VM.find(name);
     if (it == VM.end()) {
       printf("undefined variable %s\n", name);
-      throw HfstException();
+      HFST_THROW(HfstException);
     }
     free(name);
     return new HfstTransducer(*(it->second));
@@ -360,7 +360,7 @@ namespace hfst
       if (l->get_type() != r->get_type()) {
     fprintf(stderr, "ERROR: in sfst-compiler.yy:"
         " context transducers do not have the same type.\n");
-    throw HfstException();
+    HFST_THROW(HfstException);
       }
     }
 
@@ -389,7 +389,7 @@ namespace hfst
     nc->right->get_type() != c->right->get_type() ) {
       fprintf(stderr, "ERROR: in sfst-compiler.yy:"
           " context transducers do not have the same type.\n");
-      throw HfstException();
+      HFST_THROW(HfstException);
     }
     nc->next = c;
     return nc;
@@ -560,7 +560,7 @@ namespace hfst
     if (!Alphabet_Defined) {
       fprintf(stderr, "\nERROR:"
           " Two level rules require the definition of an alphabet!\n");
-      throw HfstException();
+      HFST_THROW(HfstException);
     }
 
     if (lc == NULL)
@@ -585,7 +585,7 @@ namespace hfst
       if (!Alphabet_Defined) {
     fprintf(stderr, "ERROR: The wildcard symbol '.'"
         " requires the definition of an alphabet");
-    throw HfstException();
+    HFST_THROW(HfstException);
       }
       
       // one of the ranges was '.'
@@ -793,10 +793,10 @@ namespace hfst
     break;
       default:
     fprintf(stderr, "ERROR: invalid replace type requested\n");
-    throw HfstException();
+    HFST_THROW(HfstException);
       }
     fprintf(stderr, "ERROR: in function SfstCompiler::replace\n");
-    throw HfstException();
+    HFST_THROW(HfstException);
   }
 
   HfstTransducer * SfstCompiler::make_mapping( Ranges *list1, Ranges *list2, ImplementationType type ) {
diff --git a/libhfst/src/parsers/SfstCompiler.h b/libhfst/src/parsers/SfstCompiler.h
index 412e5f5..eaba168 100644
--- a/libhfst/src/parsers/SfstCompiler.h
+++ b/libhfst/src/parsers/SfstCompiler.h
@@ -17,7 +17,6 @@
 #include "SfstAlphabet.h"
 #include <iosfwd>
 #include <fstream>
-#include <unordered_map>
 
 namespace hfst
 {
@@ -61,8 +60,9 @@ namespace hfst
       };
       
       typedef std::set<char*, ltstr> RVarSet;
-      typedef std::unordered_map<char*,HfstTransducer*> VarMap;
-      typedef std::unordered_map<char*,Range*> SVarMap;
+      // using std::(tr1::)unordered_map directive comes from SfstAlphabet.h
+      typedef unordered_map<char*,HfstTransducer*> VarMap;
+      typedef unordered_map<char*,Range*> SVarMap;
       
     private:
       VarMap VM;
diff --git a/libhfst/src/parsers/TwolcCompiler.cc b/libhfst/src/parsers/TwolcCompiler.cc
index 8e46011..750de29 100644
--- a/libhfst/src/parsers/TwolcCompiler.cc
+++ b/libhfst/src/parsers/TwolcCompiler.cc
@@ -10,7 +10,6 @@
 //   You should have received a copy of the GNU General Public License
 //   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-#include "commandline_src/CommandLine.h"
 #include "HfstTwolcDefs.h"
 #include "io_src/InputReader.h"
 #include "grammar_defs.h"
@@ -23,8 +22,8 @@ namespace hfst {
     int parse();
     void set_input(std::istream & istr);
     void set_output(std::ostream & ostr);
-    void set_warning_stream(std::ostream & ostr);
-    void set_error_stream(std::ostream & ostr);
+    void reset_lexer();
+    void reset_parser();
   }
 }
 
@@ -35,8 +34,8 @@ namespace hfst {
     void complete_alphabet(void);
     const HandyDeque<std::string> & get_total_alphabet_symbol_queue();
     const HandyDeque<std::string> & get_non_alphabet_symbol_queue();
-    void set_warning_stream(std::ostream & ostr);
-    void set_error_stream(std::ostream & ostr);
+    void reset_lexer();
+    void reset_parser();
   }
 }
 
@@ -48,69 +47,111 @@ namespace hfst {
     TwolCGrammar * get_grammar();
     void set_silent(bool val);
     void set_verbose(bool val);
-    void message(const std::string &m);
-    void set_warning_stream(std::ostream & ostr);
-    void set_error_stream(std::ostream & ostr);
+    void reset_parser();
   }
 }
 
 namespace hfst {
+  namespace twolc {
 
-  TwolcCompiler::TwolcCompiler(const CommandLine & cl, std::ostream & warn, std::ostream & error):
-    command_line(cl), warning_stream(warn), error_stream(error) {};
-
-  void TwolcCompiler::compile()
-  {
-    hfst::twolcpre1::set_input(command_line.set_input_file());
-    std::ostringstream oss1;
-    hfst::twolcpre1::set_output(oss1);
-    hfst::twolcpre1::set_warning_stream(this->warning_stream);
-    hfst::twolcpre1::set_error_stream(this->error_stream);
-    if (hfst::twolcpre1::parse() != 0)
-      {
-        throw HfstException();
-      }
-
-    std::istringstream iss1(oss1.str());
-    hfst::twolcpre2::set_input(iss1);
-    hfst::twolcpre2::set_warning_stream(this->warning_stream);
-    hfst::twolcpre2::set_error_stream(this->error_stream);
-
-    if (hfst::twolcpre2::parse() != 0)
-      {
-        throw HfstException();
-      }
-    hfst::twolcpre2::complete_alphabet();
-    std::ostringstream oss2;
-    oss2 << hfst::twolcpre2::get_total_alphabet_symbol_queue() << " ";
-    oss2 << hfst::twolcpre2::get_non_alphabet_symbol_queue();
-
-    std::istringstream iss2(oss2.str());
-    hfst::twolcpre3::set_input(iss2);
-    hfst::twolcpre3::set_warning_stream(this->warning_stream);
-    hfst::twolcpre3::set_error_stream(this->error_stream);
-      
-    OtherSymbolTransducer::set_transducer_type(command_line.format);
-    hfst::twolcpre3::set_silent(command_line.be_quiet);
-    hfst::twolcpre3::set_verbose(command_line.be_verbose);
-
-    TwolCGrammar twolc_grammar(command_line.be_quiet,
-                               command_line.be_verbose,
-                               command_line.resolve_left_conflicts,
-                               command_line.resolve_right_conflicts);
-    hfst::twolcpre3::set_grammar(&twolc_grammar);
-    if (hfst::twolcpre3::parse() != 0)
-      {
-        throw HfstException();
-      }
-  }
-   
-  void TwolcCompiler::store(HfstOutputStream & ostr)
-  {   
-    //hfst::twolcpre3::message("Compiling and storing rules.");
-    hfst::twolcpre3::get_grammar()->compile_and_store(ostr);
-  }
+    int TwolcCompiler::compile
+    (const std::string & inputfile, const std::string & outputfile,
+     bool silent, bool verbose, bool resolve_left_conflicts,
+     bool resolve_right_conflicts, hfst::ImplementationType type)
+    {
+      // Reset previous values
+      hfst::twolcpre1::reset_lexer();
+      hfst::twolcpre1::reset_parser();
 
-}
+      // (1) Preprocessing
+      std::ifstream istr(inputfile.c_str());
+      hfst::twolcpre1::set_input(istr);
+      std::ostringstream oss1;
+      hfst::twolcpre1::set_output(oss1);
+
+      try
+	{
+	  int retval = hfst::twolcpre1::parse();
+	  if (retval != 0)
+	    {
+	      return retval;
+	    }
+	}
+      catch(const HfstException & e)
+	{
+	  std::cerr << e.what() << std::endl;
+	  return -1;
+	}
+
+      // Reset previous values
+      hfst::twolcpre2::reset_lexer();
+      hfst::twolcpre2::reset_parser();
+
+      // (2) Preprocessing
+      std::istringstream iss1(oss1.str());
+      hfst::twolcpre2::set_input(iss1);
+      try
+	{
+	  int retval = hfst::twolcpre2::parse();
+	  if (retval != 0)
+	    {
+	      return retval;
+	    }
+	}
+      catch(const HfstException & e)
+	{
+	  std::cerr << e.what() << std::endl;
+	  return -1;
+	}
+
+      hfst::twolcpre2::complete_alphabet();
+
+      std::ostringstream oss2;
+      oss2 << hfst::twolcpre2::get_total_alphabet_symbol_queue() << " ";
+      oss2 << hfst::twolcpre2::get_non_alphabet_symbol_queue();
+
+      // Reset previous values
+      hfst::twolcpre3::reset_parser();
+
+      // (3) Compilation
+      try
+	{
+	  std::istringstream iss2(oss2.str());
+	  hfst::twolcpre3::set_input(iss2);
+
+	  OtherSymbolTransducer::set_transducer_type(type);
+	  hfst::twolcpre3::set_silent(silent);
+	  hfst::twolcpre3::set_verbose(verbose);
+
+	  TwolCGrammar twolc_grammar(silent,
+				     verbose,
+				     resolve_left_conflicts,
+				     resolve_right_conflicts);
+	  hfst::twolcpre3::set_grammar(&twolc_grammar);
+	  int exit_code = hfst::twolcpre3::parse();
+	  if (exit_code != 0)
+	    { return exit_code; }
+
+	  HfstOutputStream out
+	    (outputfile,type);
+	  hfst::twolcpre3::get_grammar()->compile_and_store(out);
+
+	  return exit_code;
+	}
+      catch (const HfstException e)
+	{
+	  std::cerr << "This is an hfst interface bug:" << std::endl
+		    << e() << std::endl;
+	  return -1;
+	}
+      catch (const char * s)
+	{
+	  std::cerr << "This is an a bug probably from sfst:" << std::endl
+		    << s << std::endl;
+	  return -1;
+	}
 
+    }
 
+  } // namespace twolc
+} // namespace hfst
diff --git a/libhfst/src/parsers/TwolcCompiler.h b/libhfst/src/parsers/TwolcCompiler.h
index 71cb781..282a384 100644
--- a/libhfst/src/parsers/TwolcCompiler.h
+++ b/libhfst/src/parsers/TwolcCompiler.h
@@ -10,25 +10,17 @@
 //   You should have received a copy of the GNU General Public License
 //   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-//#include "commandline_src/CommandLine.h"
-//#include "HfstTwolcDefs.h"
-//#include "io_src/InputReader.h"
-//#include "grammar_defs.h"
-//#include "rule_src/TwolCGrammar.h"
-//#include "rule_src/OtherSymbolTransducer.h"
-
 namespace hfst {
+  namespace twolc {
 
-  class TwolcCompiler
-  {
-  private:
-    CommandLine command_line;
-    std::ostream & warning_stream;
-    std::ostream & error_stream;
-  public:
-    TwolcCompiler(const CommandLine & cl, std::ostream & warn, std::ostream & error);
-    void compile();
-    void store(hfst::HfstOutputStream & ostr);
-  };
+    class TwolcCompiler
+    {
+    public:
+      static int compile
+	(const std::string & inputfile, const std::string & outputfile,
+	 bool silent, bool verbose, bool resolve_left_conflicts,
+	 bool resolve_right_conflicts, hfst::ImplementationType type);
+    };
 
-}
+  } // namespace twolc
+} // namespace hfst
diff --git a/libhfst/src/parsers/XfstCompiler.cc b/libhfst/src/parsers/XfstCompiler.cc
index 2658da7..2e9c8a4 100644
--- a/libhfst/src/parsers/XfstCompiler.cc
+++ b/libhfst/src/parsers/XfstCompiler.cc
@@ -84,7 +84,7 @@ using hfst::implementations::HfstBasicTransition;
 #define MAYBE_MINIMIZE(x) x->optimize();
 #define MAYBE_ASSERT(assertion, value) if (!value && ((variables_["assert"] == "ON" || assertion) && (variables_["quit-on-fail"] == "ON"))) { this->fail_flag_ = true; }
 #define MAYBE_QUIT if(variables_["quit-on-fail"] == "ON") { this->fail_flag_ = true; }
-
+#define CHECK_FILENAME(x) if (! this->check_filename(x)) { return *this; }
 #define EMPTY_STACK error() << "Empty stack." << std::endl; flush(&error());
 
 #define WEIGHT_PRECISION "5"
@@ -156,12 +156,13 @@ namespace xfst {
         quit_requested_(false),
         fail_flag_(false),
         output_(&std::cout),
-        error_(&std::cerr)
+        error_(&std::cerr),
 #ifdef WINDOWS
-        , winoss_stderr_(std::ostringstream()),
-        winoss_stdout_(std::ostringstream())
+        winoss_stderr_(std::ostringstream()),
+        winoss_stdout_(std::ostringstream()),
         //        redirected_stream_(NULL)
 #endif
+	restricted_mode_(false)
     {
         xre_.set_expand_definitions(true);
         xre_.set_verbosity(this->verbose_);
@@ -222,12 +223,13 @@ namespace xfst {
         quit_requested_(false),
         fail_flag_(false),
         output_(&std::cout),
-        error_(&std::cerr)
+        error_(&std::cerr),
 #ifdef WINDOWS
-        , winoss_stderr_(std::ostringstream()),
-        winoss_stdout_(std::ostringstream())
+        winoss_stderr_(std::ostringstream()),
+        winoss_stdout_(std::ostringstream()),
         //redirected_stream_(NULL)
 #endif
+	restricted_mode_(false)
     {
         xre_.set_expand_definitions(true);
         xre_.set_verbosity(this->verbose_);
@@ -1623,6 +1625,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::load_definitions(const char * infilename)
     {
+      CHECK_FILENAME(infilename);
       return this->load_stack_or_definitions
         (infilename, true /* definitions*/ );
     }
@@ -1855,6 +1858,8 @@ namespace xfst {
   XfstCompiler::convert_to_common_format
   (HfstTransducer * t, const char * filename /*=NULL*/)
   {
+    if (! this->check_filename(filename)) { return; }
+
     if (t->get_type() != format_)
       {
         if (t->get_type() == hfst::HFST_OL_TYPE ||
@@ -1901,6 +1906,7 @@ namespace xfst {
   XfstCompiler::open_hfst_input_stream(const char * infilename)
   {
     assert(infilename != NULL);
+    if (! this->check_filename(infilename)) { return NULL; }
     
     FILE * infile = hfst::hfst_fopen(infilename, "r");
     if (infile == NULL)
@@ -1941,6 +1947,7 @@ namespace xfst {
   XfstCompiler::load_stack_or_definitions
   (const char* infilename, bool load_definitions)
   {
+    CHECK_FILENAME(infilename);
     // Try to open the stream to file infilename
     HfstInputStream * instream = open_hfst_input_stream(infilename);
     IF_NULL_PROMPT_AND_RETURN_THIS(instream);
@@ -1982,6 +1989,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::load_stack(const char* infilename)
     {
+      CHECK_FILENAME(infilename);
       return this->load_stack_or_definitions(infilename, false);
     }
 
@@ -2069,6 +2077,13 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::system(const char* command)
     {
+      if (restricted_mode_)
+	{
+          error() << "Restricted mode (--restricted-mode) is in use, system calls are disabled" << std::endl;
+          flush(&error());
+          xfst_lesser_fail();
+          PROMPT_AND_RETURN_THIS;
+	}
       int rv = ::system(command);
       if (rv != 0)
         {
@@ -3908,6 +3923,26 @@ namespace xfst {
       PROMPT_AND_RETURN_THIS;
     }
 
+  bool
+  XfstCompiler::check_filename(const char * filename)
+  {
+    if (restricted_mode_)
+      {
+	std::string fn(filename);
+	if ((fn.find('/') != std::string::npos) || (fn.find('\\') != std::string::npos))
+	  {
+	    error() << "Restricted mode (--restricted-mode) is in use, write and read operations are allowed" << std::endl
+		    << "only in current directory (i.e. filenames cannot contain '/' or '\\')" << std::endl;
+	    flush(&error());
+	    xfst_lesser_fail();
+	    prompt();
+	    return false;
+	  }
+      }
+    prompt();
+    return true;
+  }
+  
   XfstCompiler&
   XfstCompiler::write_stack(const char* filename)
     {
@@ -3919,6 +3954,8 @@ namespace xfst {
         return *this;
       }
 
+    CHECK_FILENAME(filename);
+        
       HfstOutputStream* outstream = (filename != 0)?
         new HfstOutputStream(filename, stack_.top()->get_type()):
         new HfstOutputStream(stack_.top()->get_type());
@@ -4068,6 +4105,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::read_spaced_from_file(const char * filename)
     {
+      CHECK_FILENAME(filename);
       return this->read_text_or_spaced(filename, true); // spaces are used
     }
   XfstCompiler&
@@ -4081,6 +4119,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::read_text_or_spaced(const char * filename, bool spaces)
   {
+    CHECK_FILENAME(filename);
     FILE * infile = hfst::hfst_fopen(filename, "r");
     if (infile == NULL)
       {
@@ -4119,6 +4158,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::read_text_from_file(const char * filename)
     {
+      CHECK_FILENAME(filename);
       return this->read_text_or_spaced(filename, false); // spaces are not used
     }
   XfstCompiler&
@@ -4510,26 +4550,27 @@ namespace xfst {
       if (stack_.size() < 1)
         {
           EMPTY_STACK;
-          //hfst_fprintf(stderr, "Empty stack.\n");
           xfst_lesser_fail();
           return *this;
         }
 
-      HfstTransducer * result = new HfstTransducer
-        (hfst::internal_identity, hfst::internal_identity, format_);
-      HfstTransducer unk2unk
-        (hfst::internal_unknown, hfst::internal_unknown, format_);
-      result->disjunct(unk2unk);
-      result->repeat_star();
-      result->minimize(); // should be safe to minimize
-
       HfstTransducer* t = stack_.top();
-      stack_.pop();
-      result->subtract(*t);
-      delete t;
+
+      try
+	{
+	  t->negate();
+	}
+      catch (const TransducerIsNotAutomatonException & e)
+	{
+	  (void)e;
+	  error() << "Error: Negation is defined only for automata." << std::endl
+		  << "Use expression [[?:?]* - A] instead where A is the transducer to be negated." << std::endl;
+	  flush(&error());
+	  xfst_lesser_fail();
+	  return *this;
+	}
       
-      MAYBE_MINIMIZE(result);
-      stack_.push(result);
+      MAYBE_MINIMIZE(t);
       PRINT_INFO_PROMPT_AND_RETURN_THIS;
     }
   XfstCompiler&
@@ -5246,6 +5287,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::read_lexc_from_file(const char * filename)
   {
+    CHECK_FILENAME(filename);
     HfstTransducer * t = NULL;
     
     if (variables_["lexc-with-flags"] == "ON")
@@ -5317,6 +5359,7 @@ namespace xfst {
   XfstCompiler&
   XfstCompiler::read_att_from_file(const char * filename)
     {
+      CHECK_FILENAME(filename);
       FILE * infile = hfst::hfst_fopen(filename, "r");
       if (infile == NULL)
         {
@@ -5384,6 +5427,8 @@ namespace xfst {
   int
   XfstCompiler::parse(const char* filename)
     {
+      if (! this->check_filename(filename)) { return -1; }
+
       hxfstin = hfst::hfst_fopen(filename, "r");
       if (hxfstin == NULL)
         {
@@ -5425,6 +5470,19 @@ namespace xfst {
   }
 
   XfstCompiler&
+  XfstCompiler::setRestrictedMode(bool value)
+  {
+    restricted_mode_ = value;
+    return *this;
+  }
+
+  bool
+  XfstCompiler::getRestrictedMode() const
+  {
+    return restricted_mode_;
+  }
+  
+  XfstCompiler&
   XfstCompiler::print_properties(std::ostream * oss_)
     {
       std::ostream * oss = get_stream(oss_);
@@ -5481,7 +5539,7 @@ namespace xfst {
     verbose_prompt_ = verbosity;
     return *this;
   }
-
+  
   // CONSOLE
   const XfstCompiler&
   XfstCompiler::prompt()
@@ -5507,7 +5565,7 @@ namespace xfst {
     sprintf(p, "hfst[" SIZE_T_SPECIFIER "]: ", stack_.size());
     return strdup(p);
   }
-
+  
   XfstCompiler&
   XfstCompiler::print_transducer_info()
     {
diff --git a/libhfst/src/parsers/XfstCompiler.h b/libhfst/src/parsers/XfstCompiler.h
index 76c45b2..e5e31d0 100644
--- a/libhfst/src/parsers/XfstCompiler.h
+++ b/libhfst/src/parsers/XfstCompiler.h
@@ -505,6 +505,11 @@ class XfstCompiler
   //! @brief Get the prompt string.
   char* get_prompt() const;
 
+  //! @brief Allow read and write operations only in current directory, do not allow system calls.
+  XfstCompiler& setRestrictedMode(bool value);
+  //! @brief Whether restricted mode is on.
+  bool getRestrictedMode() const;
+  
   //! @brief Whether it has been requested to quit the program.
   //  Needed in interactive mode where user input is read line by line.
   bool quit_requested() const;
@@ -548,6 +553,8 @@ class XfstCompiler
   /* Flush the stream. */
   void flush(std::ostream * oss);
 
+  bool check_filename(const char * filename);
+  
  protected:
   //! @brief Get the prompt that is used when applying up or down
   //! (as specified by \a direction).
@@ -680,7 +687,7 @@ class XfstCompiler
 
   //! @brief Get the precision that is used when printing weights.
   int get_precision();
-
+  
   private:
   /* */
   const XfstCompiler& error(const char* message) const;
@@ -696,7 +703,7 @@ class XfstCompiler
 
   XfstCompiler& print_bool(bool value);
   XfstCompiler& read_prop_line(char* line);
-
+  
   /* A wrapper around stream objects, see flush(std::ostream *) for more information. */
   std::ostream * get_stream(std::ostream * oss);
 
@@ -753,6 +760,7 @@ class XfstCompiler
   // and actually written when flush(std::ostream *) is called.
   std::ostringstream winoss_stderr_;
 #endif
+  bool restricted_mode_;
 }
 ;
 
diff --git a/libhfst/src/parsers/commandline_src/CommandLine.cc b/libhfst/src/parsers/commandline_src/CommandLine.cc
index 4be392e..b0680a2 100644
--- a/libhfst/src/parsers/commandline_src/CommandLine.cc
+++ b/libhfst/src/parsers/commandline_src/CommandLine.cc
@@ -3,6 +3,7 @@
 #include "CommandLine.h"
 #include <cstring>
 #include <fstream>
+#include <cstdlib>
 
 #ifndef _MSC_VER
 #  include <getopt.h>
diff --git a/libhfst/src/parsers/compile-parsers-win.sh b/libhfst/src/parsers/compile-parsers-win.sh
new file mode 100644
index 0000000..39182e0
--- /dev/null
+++ b/libhfst/src/parsers/compile-parsers-win.sh
@@ -0,0 +1,48 @@
+
+if [ "$1" = "--help" -o "$1" = "-h" ]; then
+  echo "(For windows) Compile parsers and lexers in this directory."
+  echo "Usage:  "$0" PROGDIR [--extension EXT]"
+  echo "PROGDIR: Absolute path to directory where programs win_flex.exe"
+  echo "         and win_bison.exe are located (can be fetched from"
+  echo "         https://sourceforge.net/projects/winflexbison/)"
+  echo "EXT:     Extension used for generated C++ files (default: cc)."
+  exit 0
+fi
+
+if ! [ -d "$1" ]; then
+  echo "Error: Directory "$1" does not exist (given as first argument)."
+  exit 1
+fi
+
+if ! [ -e "$1/win_flex.exe" ]; then
+  echo "Error: win_flex.exe was not found in directory "$1" (given as first argument)."
+  exit 1
+fi
+
+if ! [ -e "$1/win_bison.exe" ]; then
+  echo "Error: win_bison.exe was not found in directory "$1" (given as first argument)."
+  exit 1
+fi
+
+EXT=cc
+if [ "$2" = "--extension" ]; then
+  EXT=$3
+fi
+
+$1/win_flex.exe --outfile=htwolcpre1-lexer.$EXT htwolcpre1-lexer.ll
+$1/win_flex.exe --outfile=htwolcpre2-lexer.$EXT htwolcpre2-lexer.ll
+$1/win_flex.exe --outfile=htwolcpre3-lexer.$EXT htwolcpre3-lexer.ll
+$1/win_flex.exe --outfile=lexc-lexer.$EXT lexc-lexer.ll
+$1/win_flex.exe --outfile=pmatch_lex.$EXT pmatch_lex.ll
+$1/win_flex.exe --outfile=sfst-scanner.$EXT sfst-scanner.ll
+$1/win_flex.exe --outfile=xfst-lexer.$EXT xfst-lexer.ll
+$1/win_flex.exe --outfile=xre_lex.$EXT xre_lex.ll
+
+$1/win_bison.exe --defines=htwolcpre1-parser.hh --output=htwolcpre1-parser.$EXT htwolcpre1-parser.yy
+$1/win_bison.exe --defines=htwolcpre2-parser.hh --output=htwolcpre2-parser.$EXT htwolcpre2-parser.yy
+$1/win_bison.exe --defines=htwolcpre3-parser.hh --output=htwolcpre3-parser.$EXT htwolcpre3-parser.yy
+$1/win_bison.exe --defines=lexc-parser.hh --output=lexc-parser.$EXT lexc-parser.yy
+$1/win_bison.exe --defines=pmatch_parse.hh --output=pmatch_parse.$EXT pmatch_parse.yy
+$1/win_bison.exe --defines=sfst-compiler.hh --output=sfst-compiler.$EXT sfst-compiler.yy
+$1/win_bison.exe --defines=xfst-parser.hh --output=xfst-parser.$EXT xfst-parser.yy
+$1/win_bison.exe --defines=xre_parse.hh --output=xre_parse.$EXT xre_parse.yy
diff --git a/libhfst/src/parsers/htwolcpre1-lexer.ll b/libhfst/src/parsers/htwolcpre1-lexer.ll
index bc50162..7c0133b 100644
--- a/libhfst/src/parsers/htwolcpre1-lexer.ll
+++ b/libhfst/src/parsers/htwolcpre1-lexer.ll
@@ -28,7 +28,7 @@
   // an object that overrides flex' default input reading.
   //#include "io_src/input_defs.h"
 
-extern int htwolcpre1error(const char*);
+extern void htwolcpre1error(const char*);
 
 #undef YY_FATAL_ERROR
 #define YY_FATAL_ERROR(msg) htwolcpre1error(msg);
@@ -65,6 +65,17 @@ result = 1; \
 
   void reduce_queue(bool variable_symbol=false);
 
+namespace hfst {
+namespace twolcpre1 {
+void reset_lexer()
+{
+  regexp_start = false;
+  htwolcpre1_rules_start = false;
+  where_seen = false;
+}
+}
+}
+
 %}
 
 RESERVED_SYMBOL	   [*+/\\=\"$?|&^\-\{\}\[\]\(\):;_!%\r\t\n~ ]
diff --git a/libhfst/src/parsers/htwolcpre1-parser.yy b/libhfst/src/parsers/htwolcpre1-parser.yy
index 41869f9..9e1b094 100644
--- a/libhfst/src/parsers/htwolcpre1-parser.yy
+++ b/libhfst/src/parsers/htwolcpre1-parser.yy
@@ -27,7 +27,6 @@
 #include "grammar_defs.h"
 #include "variable_src/RuleSymbolVector.h"
 #include "variable_src/RuleVariables.h"
-#include "common_globals.h"
 #include "../HfstExceptionDefs.h"
 
   extern int htwolcpre1lineno;
@@ -117,6 +116,29 @@ namespace hfst {
 
   // Queue for rule-matchers.
   HandyDeque<Matcher> matcher_queue;
+
+namespace hfst {
+namespace twolcpre1 {
+void reset_parser()
+{
+  output = NULL;
+  htwolcpre1_line_number = 1;
+  htwolcpre1_input_reader.reset();
+  variable_value_map = VariableValueMap();
+  rule_variables = RuleVariables();
+  //rule_symbol_vector.reset();
+  htwolcpre1_symbol_queue = HandyDeque<std::string>();
+  sets = HandySet<std::string>();
+  definitions = HandySet<std::string>();
+  set_symbols = HandyMap<std::string,std::vector<std::string> >();
+  set_name = std::string();
+  latest_set.clear();
+  htwolcpre1_inside_parenthesis = false;
+  variable_vector.clear();
+  matcher_queue = HandyDeque<Matcher>();
+}
+}
+}
 %}
 
 
@@ -223,7 +245,7 @@ NEGATIVE_RULE_CONTEXTS RULE_VARIABLES
 	("Variable rules with keyword matched have to have equal length "
 	 "variable value lists.");
       htwolcpre1error(error.c_str());
-      throw HfstException();
+      HFST_THROW(HfstException);
     }
   // Clear all containers, so that we'll be ready to handle the next rule.
   rule_symbol_vector.clear();
@@ -516,7 +538,7 @@ void htwolcpre1error(const char * text)
 {
   htwolcpre1_input_reader.error(text);
   *output << "__HFST_TWOLC_DIE";
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 
 // Set the variable of this variable initialization and set its values.
diff --git a/libhfst/src/parsers/htwolcpre2-lexer.ll b/libhfst/src/parsers/htwolcpre2-lexer.ll
index 7a88af4..8a03c50 100644
--- a/libhfst/src/parsers/htwolcpre2-lexer.ll
+++ b/libhfst/src/parsers/htwolcpre2-lexer.ll
@@ -24,7 +24,7 @@
 
 #include "../HfstExceptionDefs.h"
 
-extern int htwolcpre2error(const char*);
+extern void htwolcpre2error(const char*);
 
 #undef YY_FATAL_ERROR
 #define YY_FATAL_ERROR(msg) htwolcpre2error(msg);
@@ -58,6 +58,15 @@ result = 1; \
   // Tells whether the Alphabet section ended. It ends when the first
   // __HFST_TWOLC_; is seen.
   bool alphabet_ended = false;
+
+namespace hfst {
+namespace twolcpre2 {
+void reset_lexer()
+{
+  alphabet_ended = false;
+}
+}}
+
 %}
 
 %%
@@ -97,7 +106,7 @@ __HFST_TWOLC_KILL_SYMBOL {
   // Signifies a syntax error in the first compilation phase.
   // Just die quietly, since syntax error msgs have been issued by
   // the first compilation phase.
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 [ ] { /* space: ignore */ }
 __HFST_TWOLC_RULE_NAME=\"[^\"]+\" {
@@ -289,7 +298,7 @@ __HFST_TWOLC__ {
 __HFST_TWOLC_DIE {
   // If this symbol is seen, pass it on and exit quietly.
   //std::cout << "__HFST_TWOLC_DIE";
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 __HFST_TWOLC_SET_NAME=[^ ]+ {
   htwolcpre2_non_alphabet_symbol_queue.push_back(htwolcpre2text);
diff --git a/libhfst/src/parsers/htwolcpre2-parser.yy b/libhfst/src/parsers/htwolcpre2-parser.yy
index 7710f6f..c6485d8 100644
--- a/libhfst/src/parsers/htwolcpre2-parser.yy
+++ b/libhfst/src/parsers/htwolcpre2-parser.yy
@@ -44,6 +44,7 @@
   InputReader htwolcpre2_input_reader(htwolcpre2_line_number);
 
 namespace hfst { namespace twolcpre2 {
+
   void set_input(std::istream & istr)
   {
     htwolcpre2_input_reader.set_input(istr);
@@ -242,7 +243,7 @@ void htwolcpre2error(const char * text)
   //std::cerr << text << std::endl;
   htwolcpre2_input_reader.error(text);
   (void)text;
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 
 void htwolcpre2_semantic_error(const char * text)
@@ -273,6 +274,19 @@ const HandyDeque<std::string> & get_non_alphabet_symbol_queue()
 }
 }}
 
+namespace hfst { namespace twolcpre2 {
+
+  void reset_parser()
+  {
+    htwolcpre2_line_number = 1;
+    htwolcpre2_input_reader.reset();
+    htwolcpre2_non_alphabet_symbol_queue = HandyDeque<std::string>();
+    htwolcpre2_alphabet_symbol_queue = HandyDeque<std::string>();
+    total_alphabet_symbol_queue = HandyDeque<std::string>();
+  }
+}
+}
+
 void insert_alphabet_pairs(const HandyDeque<std::string> &symbol_queue,
 			   HandySet<SymbolPair> &symbol_pair_set)
 {
diff --git a/libhfst/src/parsers/htwolcpre3-lexer.ll b/libhfst/src/parsers/htwolcpre3-lexer.ll
index 4269955..22a0dc3 100644
--- a/libhfst/src/parsers/htwolcpre3-lexer.ll
+++ b/libhfst/src/parsers/htwolcpre3-lexer.ll
@@ -22,7 +22,7 @@
   // an object that overrides flex' default input reading.
 //#include "io_src/input_defs.h"
 
-extern int htwolcpre3error(const char*);
+extern void htwolcpre3error(const char*);
 
 #undef YY_FATAL_ERROR
 #define YY_FATAL_ERROR(msg) htwolcpre3error(msg);
@@ -67,7 +67,7 @@ __HFST_TWOLC_Sets { return SETS_DECLARATION; }
 __HFST_TWOLC_Rules { return RULES_DECLARATION; }
 __HFST_TWOLC_DIE {
   // If this symbol is seen, exit quietly.
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 [ \t\n] { /* space: ignore */ }
 
diff --git a/libhfst/src/parsers/htwolcpre3-parser.yy b/libhfst/src/parsers/htwolcpre3-parser.yy
index 24413cd..72ebc96 100644
--- a/libhfst/src/parsers/htwolcpre3-parser.yy
+++ b/libhfst/src/parsers/htwolcpre3-parser.yy
@@ -30,7 +30,6 @@
 #include "alphabet_src/Alphabet.h"
 #include "string_src/string_manipulation.h"
 #include <cstdio>
-#include "common_globals.h"
 
 #ifdef DEBUG_TWOLC_3_GRAMMAR
 #define YYDEBUG 1
@@ -77,6 +76,7 @@ namespace hfst {
   InputReader htwolcpre3_input_reader(htwolcpre3_line_number);
 
 namespace hfst { namespace twolcpre3 {
+
   void set_input(std::istream & istr)
   {
     htwolcpre3_input_reader.set_input(istr);
@@ -117,6 +117,15 @@ namespace hfst {
   {
     return grammar;
   }
+
+  void reset_parser()
+  {
+    htwolcpre3_line_number = 1;
+    htwolcpre3_input_reader.reset();
+    alphabet = Alphabet();
+    definition_map = HandyMap<std::string,OtherSymbolTransducer>();
+  }
+
 }}
 
   unsigned int get_number(const std::string &);
@@ -367,21 +376,6 @@ REGULAR_EXPRESSION: RE_LIST
   $$ = &$1->apply(&HfstTransducer::subtract,*$3);
   delete $3;
 }
-| REGULAR_EXPRESSION FREELY_INSERT RE_LIST
-{
-  $1->apply
-    (&HfstTransducer::insert_freely,
-     SymbolPair(TWOLC_FREELY_INSERT,TWOLC_FREELY_INSERT),
-     true);
-  $1->apply
-    (&HfstTransducer::substitute,
-     SymbolPair(TWOLC_FREELY_INSERT,TWOLC_FREELY_INSERT),
-     *$3,
-     true);
-  $$ = $1;
-
-  delete $3;
-}
 
 RE_LIST: /* empty */
 { $$ = new OtherSymbolTransducer(HFST_EPSILON); }
@@ -420,6 +414,21 @@ RE: PAIR
 { $$ = $2; }
 | LEFT_PARENTHESIS REGULAR_EXPRESSION RIGHT_PARENTHESIS
 { $$ = &$2->apply(&HfstTransducer::optionalize); }
+| RE FREELY_INSERT RE
+{
+  $1->apply
+    (&HfstTransducer::insert_freely,
+     SymbolPair(TWOLC_FREELY_INSERT,TWOLC_FREELY_INSERT),
+     true);
+  $1->apply
+    (&HfstTransducer::substitute,
+     SymbolPair(TWOLC_FREELY_INSERT,TWOLC_FREELY_INSERT),
+     *$3,
+     true);
+  $$ = $1;
+
+  delete $3;
+}
 
 SET_LIST: /* empty */
 | SET_LIST SET_DEFINITION
@@ -545,15 +554,15 @@ void htwolcpre3error(const char * text)
 {
   (void)text;
   htwolcpre3_input_reader.error(text);
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 
 // Print error messge and exit 1.
 void htwolcpre3_semantic_error(const char * text)
 {
   htwolcpre3_input_reader.error(text);
-  //std::cerr << std::endl << "Error: " << text << std::endl;
-  throw HfstException();
+  std::cerr << std::endl << "Error: " << text << std::endl;
+  HFST_THROW(HfstException);
 }
 
 unsigned int get_number(const std::string &s)
diff --git a/libhfst/src/parsers/io_src/InputReader.cc b/libhfst/src/parsers/io_src/InputReader.cc
index ab20ac5..fb20bec 100644
--- a/libhfst/src/parsers/io_src/InputReader.cc
+++ b/libhfst/src/parsers/io_src/InputReader.cc
@@ -25,6 +25,16 @@ InputReader::InputReader(size_t &counter):
   error_stream(NULL)
 {}
 
+void InputReader::reset()
+{
+  input_stream = NULL;
+  // counter is a reference, so it must be reset separately
+  buffer_size = 500000;
+  buffer_index = 0;
+  warning_stream = NULL;
+  error_stream = NULL;
+}
+
 void InputReader::set_input(std::istream &file)
 {
   input_stream = &file;
diff --git a/libhfst/src/parsers/io_src/InputReader.h b/libhfst/src/parsers/io_src/InputReader.h
index 37cb25f..7dfc078 100644
--- a/libhfst/src/parsers/io_src/InputReader.h
+++ b/libhfst/src/parsers/io_src/InputReader.h
@@ -61,6 +61,8 @@ public:
   //! maintained by Bison.
   InputReader(size_t &counter);
 
+  void reset();
+
   //! @brief Set the input stream from which the twolc-grmmar is read.
   void set_input(std::istream &file);
 
diff --git a/libhfst/src/parsers/pmatch_lex.ll b/libhfst/src/parsers/pmatch_lex.ll
index 7444a1d..240ea0e 100644
--- a/libhfst/src/parsers/pmatch_lex.ll
+++ b/libhfst/src/parsers/pmatch_lex.ll
@@ -74,6 +74,7 @@ UNICODE_ESCAPE ("\\u"{HEXCHAR}{HEXCHAR}{HEXCHAR}{HEXCHAR})|("\\U00"{HEXCHAR}{HEX
 "Lit(" { return LIT_LEFT; }
 "Ins(" { return INS_LEFT; }
 "EndTag(" { return ENDTAG_LEFT; }
+"Capture(" { return CAPTURE_LEFT; }
 "Cap(" { return CAP_LEFT; }
 "OptCap(" { return OPTCAP_LEFT; }
 "DownCase(" { return TOLOWER_LEFT; }
@@ -90,9 +91,12 @@ UNICODE_ESCAPE ("\\u"{HEXCHAR}{HEXCHAR}{HEXCHAR}{HEXCHAR})|("\\U00"{HEXCHAR}{HEX
 "OR(" { return OR_LEFT; }
 "AND(" { return AND_LEFT; }
 ".t(" { return TAG_LEFT; }
+".tag(" { return TAG_LEFT; }
+".with(" { return WITH_LEFT; }
 "Lst(" { return LST_LEFT; }
 "Exc(" { return EXC_LEFT; }
 "Like(" { return LIKE_LEFT; }
+"Unlike(" { return UNLIKE_LEFT; }
 "Interpolate(" { return INTERPOLATE_LEFT; }
 "Sigma(" { return SIGMA_LEFT; }
 "Counter(" { return COUNTER_LEFT; }
@@ -138,6 +142,10 @@ UNICODE_ESCAPE ("\\u"{HEXCHAR}{HEXCHAR}{HEXCHAR}{HEXCHAR})|("\\U00"{HEXCHAR}{HEX
     pmatchlval.label = strcpy((char *) malloc(strlen("max-recursion") + 1), "max-recursion");
     return VARIABLE_NAME;
 }
+"xerox-composition" {
+    pmatchlval.label = strcpy((char *) malloc(strlen("xerox-composition") + 1), "xerox-composition");
+    return VARIABLE_NAME;
+}
 
 "vector-similarity-projection-factor" {
     pmatchlval.label = strcpy((char *) malloc(strlen("vector-similarity-projection-factor") + 1), "vector-similarity-projection-factor");
@@ -286,6 +294,8 @@ UNICODE_ESCAPE ("\\u"{HEXCHAR}{HEXCHAR}{HEXCHAR}{HEXCHAR})|("\\U00"{HEXCHAR}{HEX
     return SYMBOL_WITH_LEFT_PAREN;
 }
 
+"=" { return EQUALS; }
+
 "[." { return LEFT_BRACKET_DOTTED; }
 ".]" { return RIGHT_BRACKET_DOTTED; }
 "[" { return LEFT_BRACKET; }
diff --git a/libhfst/src/parsers/pmatch_parse.yy b/libhfst/src/parsers/pmatch_parse.yy
index 6cb7c43..561003f 100644
--- a/libhfst/src/parsers/pmatch_parse.yy
+++ b/libhfst/src/parsers/pmatch_parse.yy
@@ -69,14 +69,14 @@
 %type <restrictionContext> RESTR_CONTEXT
 %type <restrictionContexts> RESTR_CONTEXTS
 %type <replType> CONTEXT_MARK
-%type <pmatchObject> INSERTION FUNCALL EXPLODE IMPLODE ENDTAG LIKE READ_FROM CONTEXT_CONDITION PMATCH_CONTEXT PMATCH_OR_CONTEXT PMATCH_AND_CONTEXT
+%type <pmatchObject> INSERTION FUNCALL EXPLODE IMPLODE ENDTAG CAPTURE LIKE READ_FROM CONTEXT_CONDITION PMATCH_CONTEXT PMATCH_OR_CONTEXT PMATCH_AND_CONTEXT
 PMATCH_RIGHT_CONTEXT PMATCH_LEFT_CONTEXT PMATCH_NEGATIVE_RIGHT_CONTEXT PMATCH_NEGATIVE_LEFT_CONTEXT
 %type <pmatchObject_vector> PMATCH_CONTEXTS
 
 %left <weight> END_OF_WEIGHTED_EXPRESSION WEIGHT
 %nonassoc <pmatchObject> CHARACTER_RANGE
 
-%left CROSS_PRODUCT COMPOSITION LENIENT_COMPOSITION INTERSECTION MERGE_RIGHT_ARROW MERGE_LEFT_ARROW
+%left CROSS_PRODUCT COMPOSITION LENIENT_COMPOSITION INTERSECTION MERGE_RIGHT_ARROW MERGE_LEFT_ARROW EQUALS
 %left CENTER_MARKER MARKUP_MARKER
 %left SHUFFLE BEFORE AFTER
 %right LEFT_ARROW RIGHT_ARROW LEFT_RIGHT_ARROW LEFT_RESTRICTION // LEFT_RESTRICTION not implemented
@@ -102,7 +102,7 @@ LTR_LONGEST_MATCH LTR_SHORTEST_MATCH
 //  MAP_LEFT
 %right DEFINE SET_VARIABLE
 LIT_LEFT INS_LEFT REGEX DEFINS DEFINED_LIST CAP_LEFT OPTCAP_LEFT OPT_TOLOWER_LEFT TOLOWER_LEFT
-OPT_TOUPPER_LEFT TOUPPER_LEFT ANY_CASE_LEFT IMPLODE_LEFT EXPLODE_LEFT DEFINE_LEFT ENDTAG_LEFT LIKE_LEFT LC_LEFT RC_LEFT NLC_LEFT NRC_LEFT OR_LEFT AND_LEFT
+OPT_TOUPPER_LEFT TOUPPER_LEFT ANY_CASE_LEFT IMPLODE_LEFT EXPLODE_LEFT DEFINE_LEFT ENDTAG_LEFT CAPTURE_LEFT LIKE_LEFT UNLIKE_LEFT LC_LEFT RC_LEFT NLC_LEFT NRC_LEFT OR_LEFT AND_LEFT WITH_LEFT
 TAG_LEFT LST_LEFT EXC_LEFT INTERPOLATE_LEFT SIGMA_LEFT COUNTER_LEFT
 %%
 
@@ -378,13 +378,21 @@ EXPRESSION12 WEIGHT { $$ = $1; $$->weight += $2; } |
 LEFT_BRACKET EXPRESSION2 RIGHT_BRACKET TAG_LEFT SYMBOL RIGHT_PARENTHESIS {
     $$ = new PmatchUnaryOperation(AddDelimiters,
                                   new PmatchBinaryOperation(Concatenate, $2,
-                                                            new PmatchString($5)));
+                                                            hfst::pmatch::make_end_tag($5)));
     free($5); } |
 LEFT_BRACKET EXPRESSION2 RIGHT_BRACKET TAG_LEFT QUOTED_LITERAL RIGHT_PARENTHESIS {
     $$ = new PmatchUnaryOperation(AddDelimiters,
                                   new PmatchBinaryOperation(Concatenate, $2,
-                                                            new PmatchString($5)));
-    free($5); };
+                                                            hfst::pmatch::make_end_tag($5)));
+    free($5); } |
+    LEFT_BRACKET EXPRESSION2 RIGHT_BRACKET WITH_LEFT SYMBOL EQUALS SYMBOL RIGHT_PARENTHESIS {
+        $$ = new PmatchBinaryOperation(
+            Concatenate,
+            new PmatchBinaryOperation(Concatenate,
+                                      hfst::pmatch::make_with_tag_entry($5, $7),
+                                      $2),
+            hfst::pmatch::make_with_tag_exit($5));
+    free($5); free($7); };
 
 EXPRESSION13:
 QUOTED_LITERAL { $$ = new PmatchString(std::string($1)); free($1); } |
@@ -503,12 +511,15 @@ INTERPOLATE_LEFT FUNCALL_ARGLIST RIGHT_PARENTHESIS { $$ = new PmatchBuiltinFunct
 SIGMA_LEFT EXPRESSION2 RIGHT_PARENTHESIS { $$ = new PmatchUnaryOperation(MakeSigma, $2); } |
 COUNTER_LEFT SYMBOL RIGHT_PARENTHESIS { $$ = hfst::pmatch::make_counter($2); free($2); } |
 ENDTAG { $$ = $1; hfst::pmatch::need_delimiters = true; } |
+CAPTURE {
+    $$ = $1;
+    hfst::pmatch::need_delimiters = true; } |
 CONTEXT_CONDITION {
     $$ = $1;
     // We will wrap the current definition with entry and exit guards
     hfst::pmatch::need_delimiters = true;
-    // Switch off the automatic separator-seeking context condition
-    hfst::pmatch::variables["need-separators"] = "off";
+    // Should we switch off the automatic separator-seeking context condition now?
+//    hfst::pmatch::variables["need-separators"] = "off";
 } |
 SYMBOL {
     std::string sym($1);
@@ -599,13 +610,36 @@ LIKE_LEFT ARGLIST RIGHT_PARENTHESIS CATENATE_N {
     if ($2->size() == 0) {
         $$ = hfst::pmatch::compile_like_arc("");
     } else if ($2->size() == 1) {
-        $$ = hfst::pmatch::compile_like_arc($2->operator[](0), "", $4);
+        $$ = hfst::pmatch::compile_like_arc($2->operator[](0), $4);
     } else {
         $$ = hfst::pmatch::compile_like_arc($2->operator[](0),
                                             $2->operator[](1), $4);
     }
     delete($2);
-}
+} |
+UNLIKE_LEFT ARGLIST RIGHT_PARENTHESIS {
+    if ($2->size() < 2) {
+        std::stringstream err;
+        err << "Unlike() operation takes exactly 2 arguments, got " << $2->size();
+        pmatcherror(err.str().c_str());
+    } else {
+        $$ = hfst::pmatch::compile_like_arc($2->operator[](1),
+                                            $2->operator[](0), 10, true);
+    }
+    delete($2);
+} |
+UNLIKE_LEFT ARGLIST RIGHT_PARENTHESIS CATENATE_N {
+    if ($2->size() < 2) {
+        std::stringstream err;
+        err << "Unlike() operation takes exactly 2 arguments, got " << $2->size();
+        pmatcherror(err.str().c_str());
+    } else {
+        $$ = hfst::pmatch::compile_like_arc($2->operator[](1),
+                                            $2->operator[](0), $4, true);
+    }
+    delete($2);
+};
+
 
 ENDTAG: ENDTAG_LEFT SYMBOL RIGHT_PARENTHESIS {
     $$ = hfst::pmatch::make_end_tag($2);
@@ -615,6 +649,24 @@ ENDTAG: ENDTAG_LEFT SYMBOL RIGHT_PARENTHESIS {
     free($2);
 };
 
+CAPTURE: CAPTURE_LEFT SYMBOL RIGHT_PARENTHESIS {
+    $$ = hfst::pmatch::make_capture_tag($2);
+    PmatchObject * captured = hfst::pmatch::make_captured_tag($2);
+    std::pair<std::string, PmatchObject*> captured_def($2, captured);
+    if (definitions.count(captured_def.first) != 0) {
+        std::stringstream warning;
+        warning << "definition of " << captured_def.first << " on line " << pmatchlineno
+                << " shadows earlier definition\n";
+        warn(warning.str());
+        delete definitions[captured_def.first];
+    }
+    definitions.insert(captured_def);
+    free($2);
+} | CAPTURE_LEFT QUOTED_LITERAL RIGHT_PARENTHESIS {
+    $$ = hfst::pmatch::make_capture_tag($2);
+    free($2);
+};
+
 READ_FROM: READ_BIN {
     std::string filepath = hfst::pmatch::path_from_filename($1);
     free($1);
@@ -672,7 +724,7 @@ READ_FROM: READ_BIN {
     free($1);
     std::string regex;
     std::string tmp;
-    std::ifstream regexfile(filepath);
+    std::ifstream regexfile(filepath.c_str());
     if (regexfile.is_open()) {
         while (getline(regexfile, tmp)) {
             regex.append(tmp);
diff --git a/libhfst/src/parsers/pmatch_utils.cc b/libhfst/src/parsers/pmatch_utils.cc
index 36d780d..1d5736d 100644
--- a/libhfst/src/parsers/pmatch_utils.cc
+++ b/libhfst/src/parsers/pmatch_utils.cc
@@ -66,7 +66,14 @@ pmatcherror(const char *msg)
 void pmatchwarning(const char *msg)
 {
     if (hfst::pmatch::verbose) {
-        std::cerr << "pmatch: "<< msg << std::endl;
+        std::string warnmsg = "pmatch: ";
+        warnmsg.append(msg);
+        warnmsg.append(" on line ");
+        std::ostringstream ss;
+        ss << pmatchlineno;
+        warnmsg.append(ss.str());
+        warnmsg.append("\n");
+        std::cerr << warnmsg;
     }
 }
 
@@ -84,12 +91,14 @@ std::set<std::string> inserted_names;
 std::set<std::string> unsatisfied_insertions;
 std::set<std::string> used_definitions;
 std::set<std::string> function_names;
+std::set<std::string> capture_names;
 std::vector<WordVector> word_vectors;
 char* startptr;
 hfst::ImplementationType format;
 size_t len;
 bool verbose;
 bool flatten;
+bool include_cosine_distances;
 std::string includedir;
 clock_t timer;
 int minimization_guard_count;
@@ -304,83 +313,122 @@ HfstTransducer * add_pmatch_delimiters(HfstTransducer * regex)
 PmatchTransducerContainer * make_end_tag(std::string tag)
 { return epsilon_to_symbol_container("@PMATCH_ENDTAG_" + tag + "@"); }
 
-struct DotProductWithWordVectorComparison {
-    WordVector compare_with_this;
-    DotProductWithWordVectorComparison(WordVector word): compare_with_this(word) {}
-    // if the vectors are normalized, dot product is == cosine similarity
-    bool operator()(WordVector left, WordVector right) {
-        WordVecFloat left_accumulator = 0;
-        WordVecFloat right_accumulator = 0;
-        for (size_t i = 0; i < compare_with_this.vector.size(); ++i) {
-            left_accumulator += compare_with_this.vector[i]*left.vector[i];
-            right_accumulator += compare_with_this.vector[i]*right.vector[i];
+PmatchTransducerContainer * make_capture_tag(std::string tag)
+{ return epsilon_to_symbol_container("@PMATCH_CAPTURE_" + tag + "@"); }
+
+PmatchTransducerContainer * make_captured_tag(std::string tag)
+{ return epsilon_to_symbol_container("@PMATCH_CAPTURED_" + tag + "@"); }
+
+PmatchObject * make_with_tag_entry(std::string key, std::string value)
+{
+    return new PmatchString("@P.PMATCH_GLOBAL_" + key + "." + value + "@");
+}
+
+PmatchObject * make_with_tag_exit(std::string key)
+{
+    return new PmatchString("@C.PMATCH_GLOBAL_" + key + "@");
+}
+
+// Get the n best candidates in the original space using an insertion sort
+std::vector<std::pair<WordVector, WordVecFloat> > get_top_n(size_t n,
+                                                            std::vector<WordVector> & vecs,
+                                                            WordVector & comparison_point)
+{
+    std::vector<std::pair<WordVector, WordVecFloat> > retval;
+    for (std::vector<WordVector>::const_iterator it = vecs.begin();
+         it != vecs.end(); ++it) {
+        WordVecFloat cosdist = cosine_distance(*it, comparison_point);
+        for (size_t i = 0; i <= retval.size(); ++i) {
+            if (i == retval.size()) {
+                // We made it to the top
+                retval.push_back(std::pair<WordVector, WordVecFloat>(
+                                     WordVector(*it), cosdist));
+                break;
+            } else {
+                // Walking the list
+                if (cosdist >= retval[i].second) {
+                    if (i == 0 && retval.size() == n) {
+                        break;
+                    }
+                    retval.insert(retval.begin() + i, std::pair<WordVector, WordVecFloat>(
+                                      WordVector(*it), cosdist));
+                    break;
+                } else {
+                    continue;
+                }
+            }
         }
-        return left_accumulator > right_accumulator;
-    }
-};
-
-struct CosineSimilarityWithWordVectorComparison {
-    WordVector compare_with_this;
-    CosineSimilarityWithWordVectorComparison(WordVector word): compare_with_this(word) {}
-    bool operator()(WordVector left, WordVector right) {
-        WordVecFloat left_accumulator = 0.0;
-        WordVecFloat right_accumulator = 0.0;
-        for (size_t i = 0; i < compare_with_this.vector.size(); ++i) {
-            left_accumulator += compare_with_this.vector[i]*left.vector[i];
-            right_accumulator += compare_with_this.vector[i]*right.vector[i];
+        if (retval.size() > n) {
+            retval.erase(retval.begin());
         }
-        left_accumulator /= left.norm;
-        right_accumulator /= right.norm;
-        return left_accumulator > right_accumulator;
     }
-};
+    return retval;    
+}
 
-std::vector<WordVecFloat> get_projected_vector(std::vector<WordVecFloat> vec,
-                                               std::vector<WordVecFloat> plane_vec,
-                                               WordVecFloat translation_term)
+// Get the n best candidates in the transformed space using an insertion sort
+std::vector<std::pair<WordVector, WordVecFloat> > get_top_n_transformed(
+    size_t n,
+    const std::vector<WordVector> & vecs,
+    std::vector<WordVecFloat> plane_vec,
+    std::vector<WordVecFloat> comparison_point,
+    WordVecFloat translation_term,
+    bool negative)
 {
-    return pointwise_plus(vec,
-                          pointwise_multiplication(
-                              (((translation_term - dot_product(vec, plane_vec)) / square_sum(plane_vec))
-                               * vector_similarity_projection_factor),
-                              plane_vec));
-}
+    std::vector<std::pair<WordVector, WordVecFloat> > retval;
+    WordVecFloat plane_vec_square_sum = square_sum(plane_vec);
+    WordVecFloat comparison_point_norm = norm(comparison_point);
+    for (std::vector<WordVector>::const_iterator it = vecs.begin();
+         it != vecs.end(); ++it) {
+        WordVector transformed_vec(*it);
 
-struct CosineSimilarityProjectedToPlaneComparison {
-    std::vector<WordVecFloat> plane_vec;
-    std::vector<WordVecFloat> comparison_point;
-    WordVecFloat translation_term;
-    WordVecFloat plane_vec_square_sum;
-    CosineSimilarityProjectedToPlaneComparison(
-        std::vector<WordVecFloat> plane_vec_, std::vector<WordVecFloat> comparison_point_, WordVecFloat translation_term_):
-        plane_vec(plane_vec_), comparison_point(comparison_point_), translation_term(translation_term_)
-        {
-            plane_vec_square_sum = square_sum(plane_vec_);
-        }
-    bool operator()(WordVector left, WordVector right) {
         /*
          * First, given a plane "plane_vec = translation term" and a point,
          * find the multiple of plane_vec which produces a vector going
          * from point to the nearest point in the plane.
          */
-        WordVecFloat left_scaler = (translation_term - dot_product(left.vector, plane_vec)) / plane_vec_square_sum;
-        WordVecFloat right_scaler = (translation_term - dot_product(right.vector, plane_vec)) / plane_vec_square_sum;
-        left_scaler *= vector_similarity_projection_factor;
-        right_scaler *= vector_similarity_projection_factor;
-        std::vector<WordVecFloat> new_left = pointwise_plus(left.vector, pointwise_multiplication(left_scaler, plane_vec));
-        std::vector<WordVecFloat> new_right = pointwise_plus(right.vector, pointwise_multiplication(right_scaler, plane_vec));
-        // Then calculate cosine similarity
-        WordVecFloat left_accumulator = 0.0;
-        WordVecFloat right_accumulator = 0.0;
-        for (size_t i = 0; i < comparison_point.size(); ++i) {
-            left_accumulator += comparison_point[i]*new_left[i];
-            right_accumulator += comparison_point[i]*new_right[i];
+
+        WordVecFloat transformed_vec_scaler =
+            (translation_term - dot_product(transformed_vec.vector, plane_vec))
+            / plane_vec_square_sum;
+        transformed_vec_scaler *= vector_similarity_projection_factor;
+        if(negative) {
+            transformed_vec.vector =
+                pointwise_minus(transformed_vec.vector,
+                                pointwise_multiplication(transformed_vec_scaler, plane_vec));
+        } else {
+            transformed_vec.vector =
+                pointwise_plus(transformed_vec.vector,
+                               pointwise_multiplication(transformed_vec_scaler, plane_vec));
+        }
+        transformed_vec.norm = norm(transformed_vec.vector);
+        WordVecFloat cosdist = 1 - dot_product(transformed_vec.vector, comparison_point)
+            / (transformed_vec.norm * comparison_point_norm);
+        for (size_t i = 0; i <= retval.size(); ++i) {
+            if (i == retval.size()) {
+                // We made it to the top
+                retval.push_back(std::pair<WordVector, WordVecFloat>(transformed_vec,
+                                                                     cosdist));
+                break;
+            } else {
+                // Walking the list
+                if (cosdist >= retval[i].second) {
+                    if (i == 0 && retval.size() == n) {
+                        break;
+                    }
+                    retval.insert(retval.begin() + i,
+                                  std::pair<WordVector, WordVecFloat>(transformed_vec, cosdist));
+                    break;
+                } else {
+                    continue;
+                }
+            }
+        }
+        if (retval.size() > n) {
+            retval.erase(retval.begin());
         }
-        left_accumulator /= norm(new_left);
-        right_accumulator /= norm(new_right);
-        return left_accumulator > right_accumulator;
     }
-};
+    return retval;    
+}
 
 template<typename T> std::vector<T> pointwise_minus(std::vector<T> l,
                                                     std::vector<T> r)
@@ -442,23 +490,52 @@ WordVecFloat cosine_distance(WordVector left, WordVector right)
     // a slightly negative distance, so make sure to return at least 0.0
     WordVecFloat retval = 1.0 - dot_product(left.vector, right.vector) /
         (left.norm * right.norm);
-    if (retval < 0.0) {
-        return 0.0;       
-    }
-    return retval;
+    return std::max(static_cast<WordVecFloat>(0.0), retval);
 }
 
 WordVecFloat cosine_distance(std::vector<WordVecFloat> left, std::vector<WordVecFloat> right)
 {
     WordVecFloat retval = 1.0 - dot_product(left, right) / (norm(left) * norm(right));
-    if (retval < 0.0) {
-        return 0.0;       
+    return std::max(static_cast<WordVecFloat>(0.0), retval);
+}
+
+// Single-word Like()
+PmatchObject * compile_like_arc(std::string word,
+                                unsigned int nwords)
+{
+    WordVector this_word;
+    for (std::vector<WordVector>::iterator it = word_vectors.begin();
+         it != word_vectors.end(); ++it) {
+        if (word == it->word) {
+            this_word = *it;
+            break;
+        }
     }
-    return retval;
+    if (this_word.word == "") {
+        // got no matches
+        PmatchString * word_o = new PmatchString(word);
+        word_o->multichar = true;
+        pmatchwarning("no matches for argument to Like() operation");
+        return word_o;
+    }
+
+    std::vector<std::pair<WordVector, WordVecFloat> > top_n = get_top_n(nwords, word_vectors, this_word);
+
+    HfstTokenizer tok;
+    HfstTransducer * retval = new HfstTransducer(format);
+    for (size_t i = 0; i < top_n.size(); ++i) {
+        HfstTransducer tmp(top_n[i].first.word, tok, format);
+        if (include_cosine_distances) {
+            tmp.set_final_weights(top_n[i].second);
+        }
+        retval->disjunct(tmp);
+    }
+    return new PmatchTransducerContainer(retval);
 }
 
+// the general case
 PmatchObject * compile_like_arc(std::string word1, std::string word2,
-                                unsigned int nwords)
+                                unsigned int nwords, bool is_negative)
 {
     WordVector this_word1;
     WordVector this_word2;
@@ -477,25 +554,27 @@ PmatchObject * compile_like_arc(std::string word1, std::string word2,
         PmatchString * word1_o = new PmatchString(word1);
         PmatchString * word2_o = new PmatchString(word2);
         word1_o->multichar = true; word2_o->multichar = true;
+        pmatchwarning("no matches for arguments to Like() operation");
         return new PmatchBinaryOperation(Disjunct, word1_o, word2_o);
     }
 
     if (this_word1.word == "" || this_word2.word == "") {
         // just one match
+        pmatchwarning("only one match for arguments to Like() operation, using nearest neighbours");
         WordVector this_word = (this_word1.word == "" ? this_word2 : this_word1);
-        CosineSimilarityWithWordVectorComparison comparison_object(this_word);
-        std::sort(word_vectors.begin(), word_vectors.end(), comparison_object);
+        std::vector<std::pair<WordVector, WordVecFloat> > top_n = get_top_n(nwords, word_vectors, this_word);
         HfstTokenizer tok;
         HfstTransducer * retval = new HfstTransducer(format);
-        for (size_t i = 0; i < word_vectors.size() && i <= nwords; ++i) {
-            HfstTransducer tmp(word_vectors[i].word, tok, format);
-            tmp.set_final_weights(cosine_distance(word_vectors[i], this_word));
+        for (size_t i = 0; i < top_n.size(); ++i) {
+            HfstTransducer tmp(top_n[i].first.word, tok, format);
+            if (include_cosine_distances) {
+                tmp.set_final_weights(top_n[i].second);
+            }
             retval->disjunct(tmp);
         }
         return new PmatchTransducerContainer(retval);
     }
 
-    // the general case
     if(variables["vector-similarity-projection-factor"] != "1.0") {
         vector_similarity_projection_factor =
             strtod(variables["vector-similarity-projection-factor"].c_str(), NULL);
@@ -513,33 +592,47 @@ PmatchObject * compile_like_arc(std::string word1, std::string word2,
      * translation term. |B - A| = 0 would be the set of vectors orthogonal to
      * |B - A|. We set d so that the distance from the hyperplane to A is
      * half of the norm of |B - A|.
+     *
      */
         
     std::vector<WordVecFloat> B_minus_A = pointwise_minus(
         this_word1.vector, this_word2.vector);
-    std::vector<WordVecFloat> halfway_point = pointwise_plus(
-        this_word2.vector, pointwise_multiplication(
-            static_cast<WordVecFloat>(0.5), B_minus_A));
     WordVecFloat hyperplane_translation_term = dot_product(B_minus_A, this_word1.vector)
         - square_sum(B_minus_A) * 0.5;
-    CosineSimilarityProjectedToPlaneComparison comparison_object(
-        B_minus_A, halfway_point, hyperplane_translation_term);
-    std::sort(word_vectors.begin(), word_vectors.end(), comparison_object);
 
+    std::vector<WordVecFloat> comparison_point;
+    if (is_negative == true) {
+        WordVecFloat comparison_scaler =
+            (hyperplane_translation_term - dot_product(this_word1.vector, B_minus_A)) / square_sum(B_minus_A);
+        comparison_scaler *= vector_similarity_projection_factor;
+        comparison_point = pointwise_minus(this_word1.vector, pointwise_multiplication(comparison_scaler, B_minus_A));
+    } else {
+        comparison_point = pointwise_plus(this_word2.vector, pointwise_multiplication(
+                                              static_cast<WordVecFloat>(0.5), B_minus_A));
+    }
+    
+    std::vector<std::pair<WordVector, WordVecFloat> > top_n = get_top_n_transformed(nwords,
+                                                                                    word_vectors,
+                                                                                    B_minus_A,
+                                                                                    comparison_point,
+                                                                                    hyperplane_translation_term,
+                                                                                    is_negative);
     HfstTokenizer tok;
     HfstTransducer * retval = new HfstTransducer(format);
-    for (size_t i = 0; i < word_vectors.size() && i <= nwords; ++i) {
-        HfstTransducer tmp(word_vectors[i].word, tok, format);
-        std::vector<WordVecFloat> projected_i = get_projected_vector(
-            word_vectors[i].vector, B_minus_A, hyperplane_translation_term);
-        tmp.set_final_weights(cosine_distance(projected_i, halfway_point));
-        retval->disjunct(tmp);
-        for (size_t j = i + 1; j < word_vectors.size() && j <= nwords; ++j) {
-            HfstTransducer tmp2(word_vectors[i].word + "_cos_" + word_vectors[j].word, tok, format);
-            tmp2.set_final_weights(cosine_distance(projected_i,
-                                                   get_projected_vector(word_vectors[j].vector, B_minus_A, hyperplane_translation_term)));
-            retval->disjunct(tmp2);
+    for (size_t i = 0; i < top_n.size() && i <= nwords; ++i) {
+        HfstTransducer tmp(top_n[i].first.word, tok, format);
+        if (include_cosine_distances) {
+            tmp.set_final_weights(top_n[i].second);
         }
+        retval->disjunct(tmp);
+        // if (include_cosine_distances) {
+        //     for (size_t j = i + 1; j < word_vectors.size() && j <= nwords; ++j) {
+        //         HfstTransducer tmp2(word_vectors[i].word + "_cos_" + word_vectors[j].word, tok, format);
+        //         tmp2.set_final_weights(cosine_distance(projected_i,
+        //                                                get_projected_vector(word_vectors[j].vector, B_minus_A, hyperplane_translation_term)));
+        //         retval->disjunct(tmp2);
+        //     }
+        // }
     }
     return new PmatchTransducerContainer(retval);
 }
@@ -547,18 +640,27 @@ PmatchObject * compile_like_arc(std::string word1, std::string word2,
 PmatchTransducerContainer * make_counter(std::string name)
 { return epsilon_to_symbol_container("@PMATCH_COUNTER_" + name + "@"); }
 
+hfst::StringSet get_non_special_alphabet(HfstTransducer * t)
+{
+    hfst::StringSet retval;
+    hfst::StringSet const & alphabet = t->get_alphabet();
+    for (hfst::StringSet::const_iterator it = alphabet.begin();
+         it != alphabet.end(); ++it) {
+        if (hfst_ol::PmatchAlphabet::is_printable(*it)) {
+            retval.insert(*it);
+        }
+    }
+    return retval;
+}
+
 HfstTransducer * make_list(HfstTransducer * t, ImplementationType f)
 {
     std::string arc = "@L.";
-    hfst::StringSet alphabet = t->get_alphabet();
+    hfst::StringSet alphabet = get_non_special_alphabet(t);
     for (hfst::StringSet::const_iterator it = alphabet.begin();
          it != alphabet.end(); ++it) {
-        if (!hfst_ol::PmatchAlphabet::is_special(*it) &&
-            *it != hfst::internal_epsilon && *it != hfst::internal_unknown &&
-            *it != hfst::internal_identity && *it != hfst::internal_default) {
-            arc.append(*it);
-            arc.append("_");
-        }
+        arc.append(*it);
+        arc.append("_");
     }
     arc.append("@");
     return new HfstTransducer(arc, f);
@@ -567,15 +669,11 @@ HfstTransducer * make_list(HfstTransducer * t, ImplementationType f)
 HfstTransducer * make_exc_list(HfstTransducer * t, ImplementationType f)
 {
     std::string arc = "@X.";
-    hfst::StringSet alphabet = t->get_alphabet();
+    hfst::StringSet alphabet = get_non_special_alphabet(t);
     for (hfst::StringSet::const_iterator it = alphabet.begin();
          it != alphabet.end(); ++it) {
-        if (!hfst_ol::PmatchAlphabet::is_special(*it) &&
-            *it != hfst::internal_epsilon && *it != hfst::internal_unknown &&
-            *it != hfst::internal_identity && *it != hfst::internal_default) {
-            arc.append(*it);
-            arc.append("_");
-        }
+        arc.append(*it);
+        arc.append("_");
     }
     arc.append("@");
     return new HfstTransducer(arc, f);
@@ -585,14 +683,10 @@ HfstTransducer * make_sigma(HfstTransducer * t)
 {
     HfstTransducer * retval =
         new HfstTransducer(format);
-    hfst::StringSet alphabet = t->get_alphabet();
+    hfst::StringSet alphabet = get_non_special_alphabet(t);
     for (hfst::StringSet::const_iterator it = alphabet.begin();
          it != alphabet.end(); ++it) {
-        if (!hfst_ol::PmatchAlphabet::is_special(*it) &&
-            *it != hfst::internal_epsilon && *it != hfst::internal_unknown &&
-            *it != hfst::internal_identity && *it != hfst::internal_default) {
             retval->disjunct(HfstTransducer(*it, format));
-        }
     }
     return retval;
 }
@@ -619,8 +713,6 @@ PmatchTransducerContainer * make_nrc_exit(void)
 { return epsilon_to_symbol_container(NRC_EXIT_SYMBOL); }
 PmatchTransducerContainer * make_nlc_exit(void)
 { return epsilon_to_symbol_container(NLC_EXIT_SYMBOL); }
-PmatchTransducerContainer * make_passthrough(void)
-{ return epsilon_to_symbol_container(PASSTHROUGH_SYMBOL); }
 
 char * get_delimited(const char *s, char delim_left, char delim_right)
 {
@@ -968,6 +1060,7 @@ void init_globals(void)
     variables["max-context-length"] = "254";
     variables["max-recursion"] =  "5000";
     variables["need-separators"] = "on";
+    variables["xerox-composition"] = "on";
     variables["vector-similarity-projection-factor"] = "1.0";
     call_stack.clear();
     def_insed_expressions.clear();
@@ -975,23 +1068,34 @@ void init_globals(void)
     unsatisfied_insertions.clear();
     used_definitions.clear();
     function_names.clear();
+    capture_names.clear();
     zero_minimization_guard();
     need_delimiters = false;
     pmatchnerrs = 0;
 }
 
+string expand_includes(const string & script)
+{
+    return string(script);
+    
+//     string filepath = hfst::pmatch::path_from_filename($1);
+}
+
 std::map<std::string, HfstTransducer*>
 compile(const string& pmatch, map<string,HfstTransducer*>& defs,
         ImplementationType impl, bool be_verbose, bool do_flatten,
+        bool do_include_cosine_distances,
         std::string includedir_)
 {
     // lock here?
     init_globals();
-    data = strdup(pmatch.c_str());
+    string expanded_script = expand_includes(pmatch);
+    data = strdup(expanded_script.c_str());
     startptr = data;
     len = strlen(data);
     verbose = be_verbose;
     flatten = do_flatten;
+    include_cosine_distances = do_include_cosine_distances;
     includedir = includedir_;
     vector_similarity_projection_factor = 1.0;
     for (map<string, HfstTransducer*>::iterator it = defs.begin();
@@ -1049,6 +1153,8 @@ compile(const string& pmatch, map<string,HfstTransducer*>& defs,
                 HfstTransducer * tmp = defs_it->second->evaluate();
                 tmp->minimize();
                 dummy.harmonize(*tmp);
+                // This is what it will be called in the archive
+                tmp->set_name(defs_it->first);
                 retval[defs_it->first] = tmp;
             }
         }
@@ -1069,10 +1175,12 @@ compile(const string& pmatch, map<string,HfstTransducer*>& defs,
             std::cerr << definitions.begin()->first << " as root\n";
             hfst::HfstTransducer * tmp = definitions.begin()->second->evaluate();
             tmp->minimize();
+            tmp->set_name("TOP");
             retval.insert(std::pair<std::string, hfst::HfstTransducer*>("TOP", tmp));
         } else {
             hfst::HfstTransducer * tmp = definitions["TOP"]->evaluate();
             tmp->minimize();
+            tmp->set_name("TOP");
             retval.insert(std::pair<std::string, hfst::HfstTransducer*>("TOP", tmp));
         }
     }
@@ -1091,8 +1199,11 @@ compile(const string& pmatch, map<string,HfstTransducer*>& defs,
         begins_and_ends_with_non_whitespace.concatenate(anything);
         begins_and_ends_with_non_whitespace.concatenate(not_whitespace);
         begins_and_ends_with_non_whitespace.compose(*(retval["TOP"]));
+        HfstTransducer is_single_non_whitespace(not_whitespace);
+        is_single_non_whitespace.compose(*(retval["TOP"]));
         HfstTransducer empty(format);
-        if (begins_and_ends_with_non_whitespace.compare(empty) == false) {
+        if (begins_and_ends_with_non_whitespace.compare(empty) == false ||
+            is_single_non_whitespace.compare(empty) == false) {
             HfstTransducer whitespace_punct_context(*(get_utils()->latin1_whitespace_acceptor));
             whitespace_punct_context.disjunct(*(get_utils()->latin1_punct_acceptor));
             whitespace_punct_context.disjunct(HfstTransducer("@BOUNDARY@", format));
@@ -1106,6 +1217,13 @@ compile(const string& pmatch, map<string,HfstTransducer*>& defs,
             top_with_boundaries->concatenate(RC);
             delete retval["TOP"];
             retval["TOP"] = add_pmatch_delimiters(top_with_boundaries);
+            (retval["TOP"])->minimize();
+            if (hfst::pmatch::verbose) {
+                double duration = (clock() - hfst::pmatch::timer) /
+                    (double) CLOCKS_PER_SEC;
+                hfst::pmatch::timer = clock();
+                std::cerr << "added automatic context separators in " << duration << " seconds\n";
+            }
         }
     }
     for(std::map<std::string, std::string>::iterator it = variables.begin();
@@ -1140,7 +1258,7 @@ HfstTransducer * read_text(std::string filename, ImplementationType type,
 {
     std::ifstream infile;
     std::string line;
-    infile.open(filename);
+    infile.open(filename.c_str());
     HfstTokenizer tok;
     HfstTransducer * retval = new HfstTransducer(type);
     if(!infile.good()) {
@@ -1192,7 +1310,7 @@ void read_vec(std::string filename)
     std::string line;
     size_t linenumber = 0;
     char separator = '\t';
-    infile.open(filename);
+    infile.open(filename.c_str());
     if(!infile.good()) {
         std::cerr << "pmatch: could not open vector file " << filename <<
             " for reading\n";
@@ -1222,8 +1340,16 @@ void read_vec(std::string filename)
             }
             // there can be one more from pos to the newline if there isn't a
             // separator at the end
+#if defined(NO_CPLUSPLUS_11)
+            if (*(line.rbegin()) != separator) {
+#else
             if (line.back() != separator) {
-                components.push_back(strtof(line.substr(pos + 1).c_str(), NULL));
+#endif
+#if defined _MSC_VER && 1200 <= _MSC_VER
+	      components.push_back((float)strtod(line.substr(pos + 1).c_str(), NULL));
+#else
+	      components.push_back(strtof(line.substr(pos + 1).c_str(), NULL));
+#endif
             }
             if (word_vectors.size() != 0 && word_vectors[0].vector.size() != components.size()) {
                 std::cerr << "pmatch warning: vector file " << filename <<
@@ -1471,6 +1597,7 @@ HfstTransducer * PmatchUtilityTransducers::cap(HfstTransducer & t, Side side, bo
         continuation2.repeat_star();
         cap.concatenate(continuation2);
         retval->compose(cap);
+        retval->output_project();
     }
     retval->minimize();
     return retval;
@@ -1786,7 +1913,11 @@ HfstTransducer * PmatchUnaryOperation::evaluate(PmatchEvalType eval_type)
     } else if (op == TermComplement) {
         HfstTransducer* any = new HfstTransducer(hfst::internal_identity,
                                                  hfst::pmatch::format);
-        any->subtract(*retval);
+        hfst::StringSet alphabet = get_non_special_alphabet(retval);
+        for (hfst::StringSet::iterator it = alphabet.begin(); it != alphabet.end(); ++it) {
+            HfstTransducer symbol(*it, hfst::pmatch::format);
+            any->subtract(symbol);
+        }
         delete retval;
         retval = any;
     } else if (op == Cap) {
@@ -1913,7 +2044,7 @@ HfstTransducer * PmatchUnaryOperation::evaluate(PmatchEvalType eval_type)
             retval->reverse();
             PmatchTransducerContainer * tmp = make_minimization_guard();
             HfstTransducer * head = tmp->evaluate(); delete tmp;
-            HfstTransducer passthrough(hfst::internal_epsilon, PASSTHROUGH_SYMBOL, format);
+            HfstTransducer passthrough(PASSTHROUGH_SYMBOL, format);
             HfstTransducer nlc_entry(hfst::internal_epsilon, NLC_ENTRY_SYMBOL, format);
             HfstTransducer nlc_exit(hfst::internal_epsilon, NLC_EXIT_SYMBOL, format);
             nlc_entry.concatenate(*retval);
@@ -1936,13 +2067,13 @@ HfstTransducer * PmatchUnaryOperation::evaluate(PmatchEvalType eval_type)
         if (!parent_is_context) {
             PmatchTransducerContainer * tmp = make_minimization_guard();
             HfstTransducer * head = tmp->evaluate(); delete tmp;
-            HfstTransducer passthrough(hfst::internal_epsilon, PASSTHROUGH_SYMBOL, format);
-            HfstTransducer nlc_entry(hfst::internal_epsilon, NLC_ENTRY_SYMBOL, format);
-            HfstTransducer nlc_exit(hfst::internal_epsilon, NLC_EXIT_SYMBOL, format);
-            nlc_entry.concatenate(*retval);
-            nlc_entry.concatenate(nlc_exit);
-            nlc_entry.disjunct(passthrough);
-            head->concatenate(nlc_entry);
+            HfstTransducer passthrough(PASSTHROUGH_SYMBOL, format);
+            HfstTransducer nrc_entry(hfst::internal_epsilon, NRC_ENTRY_SYMBOL, format);
+            HfstTransducer nrc_exit(hfst::internal_epsilon, NRC_EXIT_SYMBOL, format);
+            nrc_entry.concatenate(*retval);
+            nrc_entry.concatenate(nrc_exit);
+            nrc_entry.disjunct(passthrough);
+            head->concatenate(nrc_entry);
             delete retval;
             retval = head;
             }
diff --git a/libhfst/src/parsers/pmatch_utils.h b/libhfst/src/parsers/pmatch_utils.h
index abf245c..0975d12 100644
--- a/libhfst/src/parsers/pmatch_utils.h
+++ b/libhfst/src/parsers/pmatch_utils.h
@@ -22,6 +22,7 @@
 #include <time.h>
 #include <iomanip>
 #include <cmath>
+#include <algorithm>
 #include "HfstTransducer.h"
 #include "HfstXeroxRules.h"
 #include "xre_utils.h"
@@ -49,10 +50,12 @@ extern std::set<std::string> inserted_names;
 extern std::set<std::string> unsatisfied_insertions;
 extern std::set<std::string> used_definitions;
 extern std::set<std::string> function_names;
+extern std::set<std::string> capture_names;
 extern std::vector<WordVector> word_vectors;
 extern ImplementationType format;
 extern bool verbose;
 extern bool flatten;
+extern bool include_cosine_distances;
 extern std::string includedir;
 extern clock_t timer;
 extern int minimization_guard_count;
@@ -126,6 +129,24 @@ HfstTransducer * add_pmatch_delimiters(HfstTransducer * regex);
  */
 PmatchTransducerContainer * epsilon_to_symbol_container(std::string s);
 PmatchTransducerContainer * make_end_tag(std::string tag);
+PmatchTransducerContainer * make_capture_tag(std::string tag);
+PmatchTransducerContainer * make_captured_tag(std::string tag);
+PmatchObject * make_with_tag_entry(std::string key, std::string value);
+PmatchObject * make_with_tag_exit(std::string key);
+
+std::vector<std::pair<WordVector, WordVecFloat> > get_top_n(
+    size_t n,
+    const std::vector<WordVector> & vecs,
+    WordVector & comparison_point);
+
+std::vector<std::pair<WordVector, WordVecFloat> > get_top_n_transformed(
+    size_t n,
+    const std::vector<WordVector> & vecs,
+    std::vector<WordVecFloat> plane_vec,
+    std::vector<WordVecFloat> comparison_point,
+    WordVecFloat translation_term,
+    bool negative);
+
 template<typename T> std::vector<T> pointwise_minus(std::vector<T> l,
                                                     std::vector<T> r);
 template<typename T> std::vector<T> pointwise_plus(std::vector<T> l,
@@ -137,9 +158,14 @@ template<typename T> T dot_product(std::vector<T> l,
 template<typename T> T square_sum(std::vector<T> v);
 template<typename T> T norm(std::vector<T> v);
 WordVecFloat cosine_distance(WordVector left, WordVector right);
-PmatchObject * compile_like_arc(std::string word1, std::string word2 = "",
-    unsigned int nwords = 10);
+PmatchObject * compile_like_arc(std::string word1, std::string word2,
+                                unsigned int nwords = 10, bool is_negative = false);
+PmatchObject * compile_like_arc(std::string word,
+                                unsigned int nwords = 10);
+
 PmatchTransducerContainer * make_counter(std::string name);
+
+hfst::StringSet get_non_special_alphabet(HfstTransducer * t);
 HfstTransducer * make_list(HfstTransducer * t,
                            ImplementationType f = format);
 HfstTransducer * make_exc_list(HfstTransducer * t,
@@ -177,6 +203,8 @@ double get_weight(const char* s);
 
 void init_globals(void);
 
+string expand_includes(const string & script);
+
 /**
  * @brief compile new transducer
  */
@@ -185,6 +213,7 @@ std::map<std::string, HfstTransducer*>
             std::map<std::string,hfst::HfstTransducer*>& defs,
             hfst::ImplementationType type,
             bool be_verbose = false, bool do_flatten = false,
+            bool include_cosine_distances = false,
             std::string includedir = "");
 
 void print_size_info(HfstTransducer * net);
@@ -611,6 +640,9 @@ struct PmatchTransducerContainer: public PmatchObject{
         }
         HfstTransducer * retval = new HfstTransducer(*t);
         retval->set_final_weights(hfst::double_to_float(weight), true);
+        if (name != "") {
+            retval->set_name(name);
+        }
         return retval;
     }
 };
diff --git a/libhfst/src/parsers/sfst-compiler.yy b/libhfst/src/parsers/sfst-compiler.yy
index 1c6533d..a1f5e6c 100644
--- a/libhfst/src/parsers/sfst-compiler.yy
+++ b/libhfst/src/parsers/sfst-compiler.yy
@@ -33,7 +33,7 @@ void sfsterror(char *text)
 {
   cerr << "\n" << sfst_compiler->filename << ":" << sfstlineno << ": " << text << " at: ";
   cerr << sfsttext << "\naborted.\n";
-  throw HfstException();
+  HFST_THROW(HfstException);
 }
 
 void warn(char *text)
@@ -147,7 +147,7 @@ RE:         RE ARROW CONTEXTS2      { $$ = sfst_compiler->restriction($1,$2,$3,0
           | RE '|' RE        { $1->disjunct(*$3); delete $3; $$ = $1; }
           | '(' RE ')'       { $$ = $2; }
           | STRING           { $$ = sfst_compiler->read_words(sfst_compiler->foldername.c_str(), $1, sfst_compiler->compiler_type); }
-          | STRING2          { try { $$ = sfst_compiler->read_transducer(sfst_compiler->foldername.c_str(), $1, sfst_compiler->compiler_type); } catch (HfstException e) { printf("\nAn error happened when reading file \"%s\"\n", $1); throw HfstException(); } }
+          | STRING2          { try { $$ = sfst_compiler->read_transducer(sfst_compiler->foldername.c_str(), $1, sfst_compiler->compiler_type); } catch (HfstException e) { printf("\nAn error happened when reading file \"%s\"\n", $1);   HFST_THROW(HfstException); } }
           ;
 
 RANGES:     RANGE RANGES     { $$ = sfst_compiler->add_range($1,$2); }
diff --git a/libhfst/src/parsers/sfst-scanner.ll b/libhfst/src/parsers/sfst-scanner.ll
index abc1d84..574e6dc 100644
--- a/libhfst/src/parsers/sfst-scanner.ll
+++ b/libhfst/src/parsers/sfst-scanner.ll
@@ -97,7 +97,7 @@ FN	[A-Za-z0-9._/\-*+]
 		     name[strlen(name)-1] = 0;
                      if ( Include_Stack_Ptr >= MAX_INCLUDE_DEPTH ) {
 		       fprintf( stderr, "Includes nested too deeply" );
-                       throw HfstException();
+                       HFST_THROW(HfstException);
 		     }
 		     if (sfst_compiler->Verbose) fputc('\n', stderr);
 		     file = fopen( name, "rt" );
diff --git a/libhfst/src/parsers/xfst-lexer.ll b/libhfst/src/parsers/xfst-lexer.ll
index 8cc93e1..c9629bc 100644
--- a/libhfst/src/parsers/xfst-lexer.ll
+++ b/libhfst/src/parsers/xfst-lexer.ll
@@ -243,12 +243,12 @@ LWSP [\t ]*
 
 "echo"{WSP}+.* {
     hxfstlval.text = hfst::xfst::strstrip(hxfsttext + strlen("echo "));
-    return ECHO;
+    return ECHO_;
 }
 
 ^{LWSP}"echo"{WSP}* {
     hxfstlval.text = strdup("");
-    return ECHO;
+    return ECHO_;
 }
 
 ^{LWSP}("edit properties"|"edit") {
diff --git a/libhfst/src/parsers/xfst-parser.yy b/libhfst/src/parsers/xfst-parser.yy
index ab9301c..188105a 100644
--- a/libhfst/src/parsers/xfst-parser.yy
+++ b/libhfst/src/parsers/xfst-parser.yy
@@ -56,7 +56,7 @@ int hxfstlex(void);
     void* nothing;
 }
 
-%token <text> APROPOS DESCRIBE ECHO SYSTEM QUIT HFST
+%token <text> APROPOS DESCRIBE ECHO_ SYSTEM QUIT HFST
 %token <name> NAMETOKEN NAMECHAR GLOB PROTOTYPE
               DEFINE_NAME DEFINE_FUNCTION
 %token <list> RANGE
@@ -104,9 +104,13 @@ COMMAND_LIST: COMMAND_LIST COMMAND
             ;
 
 COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->add_props(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->add_props(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | ADD_PROPS NAMETOKEN_LIST CTRLD {
             hfst::xfst::xfst_->add_props($2);
@@ -128,9 +132,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | APPLY_UP REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->apply_up(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->apply_up(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | APPLY_UP END_COMMAND NAMETOKEN_LIST END_SUB {
             hfst::xfst::xfst_->apply_up($3);
@@ -147,9 +155,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | APPLY_DOWN REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->apply_down(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->apply_down(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | APPLY_DOWN END_COMMAND NAMETOKEN_LIST END_SUB {
             hfst::xfst::xfst_->apply_down($3);
@@ -160,9 +172,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | APPLY_MED REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->apply_med(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->apply_med(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | APPLY_MED END_COMMAND NAMETOKEN_LIST END_SUB {
             hfst::xfst::xfst_->apply_med($3);
@@ -296,7 +312,7 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->eliminate_flags(); CHECK;
        }
        // system
-       | ECHO {
+       | ECHO_ {
             hfst::xfst::xfst_->echo($1);
             free($1); CHECK;
        }
@@ -438,17 +454,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
        }
        // prints
        | PRINT_ALIASES REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_aliases(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_aliases(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_ALIASES END_COMMAND {
             hfst::xfst::xfst_->print_aliases(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_ARCCOUNT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_arc_count(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_arc_count(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_ARCCOUNT NAMETOKEN END_COMMAND {
             if (strcmp($2, "upper") && strcmp($2, "lower"))
@@ -464,17 +488,24 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_arc_count(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_DEFINED REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_defined(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+            {
+	      std::ofstream oss($2);
+              hfst::xfst::xfst_->print_defined(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_DEFINED END_COMMAND {
             hfst::xfst::xfst_->print_defined(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_DIR GLOB REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($3);
-            hfst::xfst::xfst_->print_dir($2, &oss);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+            {
+	      std::ofstream oss($3);
+              hfst::xfst::xfst_->print_dir($2, &oss);
+              oss.close();
+	    }
             free($3); CHECK;
        }
        | PRINT_DIR GLOB END_COMMAND {
@@ -482,25 +513,37 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_DIR REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_dir("*", &oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_dir("*", &oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_DIR END_COMMAND {
             hfst::xfst::xfst_->print_dir("*", &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_FILE_INFO REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_file_info(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+            {
+	      std::ofstream oss($2);
+              hfst::xfst::xfst_->print_file_info(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_FILE_INFO END_COMMAND {
             hfst::xfst::xfst_->print_file_info(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_FLAGS REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_flags(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_flags(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_FLAGS END_COMMAND {
             hfst::xfst::xfst_->print_flags(&hfst::xfst::xfst_->get_output_stream()); CHECK;
@@ -510,25 +553,36 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_LABELS REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_labels(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+            {
+	      std::ofstream oss($2);
+              hfst::xfst::xfst_->print_labels(&oss);
+              oss.close();
+	      }
+	      CHECK;
        }
        | PRINT_LABELS END_COMMAND {
             hfst::xfst::xfst_->print_labels(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_LABEL_COUNT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_label_count(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_label_count(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_LABEL_COUNT END_COMMAND {
             hfst::xfst::xfst_->print_label_count(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_LIST NAMETOKEN REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($3);
-            hfst::xfst::xfst_->print_list($2, &oss);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              hfst::xfst::xfst_->print_list($2, &oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_LIST NAMETOKEN END_COMMAND {
@@ -536,19 +590,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_LISTS REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_list(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+            {
+	      std::ofstream oss($2);
+              hfst::xfst::xfst_->print_list(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_LISTS END_COMMAND {
             hfst::xfst::xfst_->print_list(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_LONGEST_STRING REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_longest_string(&oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_longest_string(&oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_LONGEST_STRING END_COMMAND {
@@ -557,11 +617,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             CHECK;
        }
        | PRINT_LONGEST_STRING_SIZE REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_longest_string_size(&oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+            {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_longest_string_size(&oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_LONGEST_STRING_SIZE END_COMMAND {
@@ -570,19 +632,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             CHECK;
        }
        | PRINT_NAME REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_name(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_name(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_NAME END_COMMAND {
             hfst::xfst::xfst_->print_name(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_SHORTEST_STRING REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_shortest_string(&oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_shortest_string(&oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_SHORTEST_STRING END_COMMAND {
@@ -591,11 +659,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             CHECK;
        }
        | PRINT_SHORTEST_STRING_SIZE REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_shortest_string_size(&oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_shortest_string_size(&oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_SHORTEST_STRING_SIZE END_COMMAND {
@@ -608,12 +678,14 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); free($3); CHECK;
        }
        | PRINT_LOWER_WORDS NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_lower_words($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            //hfst::xfst::xfst_fclose(f, $4);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($4))
+	    {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_lower_words($2, hfst::xfst::nametoken_to_number($3), &oss);
+              //hfst::xfst::xfst_fclose(f, $4);
+              oss.close();
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_LOWER_WORDS NAMETOKEN END_COMMAND {
@@ -629,24 +701,28 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_lower_words(NULL, 0, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_LOWER_WORDS NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_lower_words(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_lower_words($2, 0, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_lower_words(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_lower_words($2, 0, &oss);
+              //hfst::xfst::xfst_fclose(f, $3);
+              oss.close();
+	    }
             free($2);
             CHECK;
        }
        | PRINT_LOWER_WORDS REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_lower_words(NULL, 0, &oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_lower_words(NULL, 0, &oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_RANDOM_LOWER NAMETOKEN NAMETOKEN END_COMMAND {
@@ -654,12 +730,14 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); free($3); CHECK;
        }
        | PRINT_RANDOM_LOWER NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_random_lower($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            oss.close();
-            //hfst::xfst::xfst_fclose(f, $4);
+            if (hfst::xfst::xfst_->check_filename($4))
+            {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_random_lower($2, hfst::xfst::nametoken_to_number($3), &oss);
+              oss.close();
+	      //hfst::xfst::xfst_fclose(f, $4);
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_RANDOM_LOWER NAMETOKEN END_COMMAND {
@@ -674,23 +752,27 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_random_lower(NULL, 15, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_RANDOM_LOWER NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_random_lower(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_random_lower($2, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_random_lower(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_random_lower($2, 15, &oss);
+              //hfst::xfst::xfst_fclose(f, $3);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_RANDOM_LOWER REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_random_lower(NULL, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_random_lower(NULL, 15, &oss);
+              //hfst::xfst::xfst_fclose(f, $2);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_UPPER_WORDS NAMETOKEN NAMETOKEN END_COMMAND {
@@ -698,12 +780,14 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_UPPER_WORDS NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_upper_words($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            //hfst::xfst::xfst_fclose(f, $4);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($4))
+	    {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_upper_words($2, hfst::xfst::nametoken_to_number($3), &oss);
+              //hfst::xfst::xfst_fclose(f, $4);
+              oss.close();
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_UPPER_WORDS NAMETOKEN END_COMMAND {
@@ -718,23 +802,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_upper_words(NULL, 0, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_UPPER_WORDS NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_upper_words(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_upper_words($2, 0, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_upper_words(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_upper_words($2, 0, &oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_UPPER_WORDS REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_upper_words(NULL, 0, &oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_upper_words(NULL, 0, &oss);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_RANDOM_UPPER NAMETOKEN NAMETOKEN END_COMMAND {
@@ -742,12 +828,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); free($3); CHECK;
        }
        | PRINT_RANDOM_UPPER NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_random_upper($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            //hfst::xfst::xfst_fclose(f, $4);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($4))
+	    {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_random_upper($2, hfst::xfst::nametoken_to_number($3), &oss);
+              oss.close();
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_RANDOM_UPPER NAMETOKEN END_COMMAND {
@@ -762,23 +849,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_random_upper(NULL, 15, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_RANDOM_UPPER NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_random_upper(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_random_upper($2, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+            {
+	      std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_random_upper(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_random_upper($2, 15, &oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_RANDOM_UPPER REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_random_upper(NULL, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_random_upper(NULL, 15, &oss);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_WORDS NAMETOKEN NAMETOKEN END_COMMAND {
@@ -786,12 +875,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); free($3); CHECK;
        }
        | PRINT_WORDS NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_words($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            //hfst::xfst::xfst_fclose(f, $4);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($4))
+	    {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_words($2, hfst::xfst::nametoken_to_number($3), &oss);
+              oss.close();
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_WORDS NAMETOKEN END_COMMAND {
@@ -806,23 +896,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_words(NULL, 0, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_WORDS NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_words(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_words($2, 0, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_words(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_words($2, 0, &oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_WORDS REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_words(NULL, 0, &oss);
-            oss.close();
-            //hfst::xfst::xfst_fclose(f, $2);
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_words(NULL, 0, &oss);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT_RANDOM_WORDS NAMETOKEN NAMETOKEN END_COMMAND {
@@ -830,12 +922,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); free($3); CHECK;
        }
        | PRINT_RANDOM_WORDS NAMETOKEN NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($4, "w");
-            std::ofstream oss($4);
-            hfst::xfst::xfst_->print_random_words($2, hfst::xfst::nametoken_to_number($3), &oss);
-            free($2); free($3);
-            //hfst::xfst::xfst_fclose(f, $4);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($4))
+	    {
+              std::ofstream oss($4);
+              hfst::xfst::xfst_->print_random_words($2, hfst::xfst::nametoken_to_number($3), &oss);
+              oss.close();
+	    }
+	    free($2); free($3);
             CHECK;
        }
        | PRINT_RANDOM_WORDS NAMETOKEN END_COMMAND {
@@ -850,23 +943,25 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_random_words(NULL, 15, &hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_RANDOM_WORDS NAMETOKEN REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($3);
-            std::ofstream oss($3);
-            int i = hfst::xfst::nametoken_to_number($2);
-            if (i != -1)
-              hfst::xfst::xfst_->print_random_words(NULL, i, &oss);
-            else
-              hfst::xfst::xfst_->print_random_words($2, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $3);
+            if (hfst::xfst::xfst_->check_filename($3))
+	    {
+              std::ofstream oss($3);
+              int i = hfst::xfst::nametoken_to_number($2);
+              if (i != -1)
+                hfst::xfst::xfst_->print_random_words(NULL, i, &oss);
+              else
+                hfst::xfst::xfst_->print_random_words($2, 15, &oss);
             oss.close();
+	    }
             free($2); CHECK;
        }
        | PRINT_RANDOM_WORDS REDIRECT_OUT END_COMMAND {
-            //std::ofstream oss($2);
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_random_words(NULL, 15, &oss);
-            //hfst::xfst::xfst_fclose(f, $2);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_random_words(NULL, 15, &oss);
+              oss.close();
+	    }
             CHECK;
        }
        | PRINT NAMETOKEN END_COMMAND {
@@ -874,9 +969,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_net(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_net(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT END_COMMAND {
             hfst::xfst::xfst_->print_net(&hfst::xfst::xfst_->get_output_stream()); CHECK;
@@ -889,26 +988,38 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->print_properties(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_PROPS REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_properties(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_properties(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_SIGMA NAMETOKEN END_COMMAND {
             hfst::xfst::xfst_->print_sigma($2, &hfst::xfst::xfst_->get_output_stream());
             free($2); CHECK;
        }
        | PRINT_SIGMA REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_sigma(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_sigma(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_SIGMA END_COMMAND {
             hfst::xfst::xfst_->print_sigma(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_SIGMA_COUNT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_sigma_count(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_sigma_count(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_SIGMA_COUNT END_COMMAND {
             hfst::xfst::xfst_->print_sigma_count(&hfst::xfst::xfst_->get_output_stream()); CHECK;
@@ -924,9 +1035,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_SIGMA_WORD_COUNT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_sigma_word_count(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_sigma_word_count(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_SIGMA_WORD_COUNT END_COMMAND {
             hfst::xfst::xfst_->print_sigma_word_count(&hfst::xfst::xfst_->get_output_stream()); CHECK;
@@ -936,25 +1051,37 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | PRINT_SIZE REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_size(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_size(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_SIZE END_COMMAND {
             hfst::xfst::xfst_->print_size(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_STACK REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_stack(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_stack(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | PRINT_STACK END_COMMAND {
             hfst::xfst::xfst_->print_stack(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | PRINT_LABELMAPS REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->print_labelmaps(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->print_labelmaps(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        // writes
        | SAVE_DOT NAMETOKEN END_COMMAND {
@@ -962,9 +1089,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | SAVE_DOT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_dot(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_dot(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | SAVE_DOT END_COMMAND {
             hfst::xfst::xfst_->write_dot(&hfst::xfst::xfst_->get_output_stream()); CHECK;
@@ -996,47 +1127,71 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | SAVE_PROLOG REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_prolog(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_prolog(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | SAVE_PROLOG NAMETOKEN END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_prolog(&oss);
-            oss.close(); free($2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_prolog(&oss);
+              oss.close();
+	    }
+	    free($2); CHECK;
        }
        | SAVE_PROLOG END_COMMAND {
             hfst::xfst::xfst_->write_prolog(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | SAVE_SPACED REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_spaced(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_spaced(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | SAVE_SPACED END_COMMAND {
             hfst::xfst::xfst_->write_spaced(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | SAVE_TEXT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_text(&oss);
-            oss.close(); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_text(&oss);
+              oss.close();
+	    }
+	    CHECK;
        }
        | SAVE_TEXT END_COMMAND {
             hfst::xfst::xfst_->write_text(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        // reads
        | READ_PROPS REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->read_props(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->read_props(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | READ_PROPS END_COMMAND {
             hfst::xfst::xfst_->read_props(stdin); CHECK;
        }
        | READ_PROLOG NAMETOKEN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->read_prolog(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); free($2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->read_prolog(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    free($2); CHECK;
        }
        | READ_PROLOG END_COMMAND {
             hfst::xfst::xfst_->read_prolog(stdin); CHECK;
@@ -1046,9 +1201,13 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             free($2); CHECK;
        }
        | READ_REGEX REDIRECT_IN END_COMMAND {
-            FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
-            hfst::xfst::xfst_->read_regex(f);
-            hfst::xfst::xfst_->xfst_fclose(f, $2); CHECK;
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              FILE * f = hfst::xfst::xfst_->xfst_fopen($2, "r"); CHECK;
+              hfst::xfst::xfst_->read_regex(f);
+              hfst::xfst::xfst_->xfst_fclose(f, $2);
+	    }
+	    CHECK;
        }
        | READ_REGEX NAMETOKEN_LIST SEMICOLON END_COMMAND {
             hfst::xfst::xfst_->read_regex($2);
@@ -1097,22 +1256,31 @@ COMMAND: ADD_PROPS REDIRECT_IN END_COMMAND {
             hfst::xfst::xfst_->write_att(&hfst::xfst::xfst_->get_output_stream()); CHECK;
        }
        | WRITE_ATT REDIRECT_OUT END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_att(&oss);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_att(&oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | WRITE_ATT NAMETOKEN END_COMMAND {
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_att(&oss);
-            oss.close();
+            if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_att(&oss);
+              oss.close();
+	    }
             free($2); CHECK;
        }
        | WRITE_ATT NAMETOKEN NAMETOKEN NAMETOKEN END_COMMAND {
             // todo: handle input and output symbol tables
-            std::ofstream oss($2);
-            hfst::xfst::xfst_->write_att(&oss);
-            oss.close();
+	    if (hfst::xfst::xfst_->check_filename($2))
+	    {
+              std::ofstream oss($2);
+              hfst::xfst::xfst_->write_att(&oss);
+              oss.close();
+	    }
             free($2); free($3); free($4); CHECK;
        }
        // net ops
diff --git a/libhfst/src/parsers/xre_parse.yy b/libhfst/src/parsers/xre_parse.yy
index 8a32471..c93449b 100644
--- a/libhfst/src/parsers/xre_parse.yy
+++ b/libhfst/src/parsers/xre_parse.yy
@@ -849,7 +849,13 @@ REGEXP7: REGEXP8 { $$ = $1; }
 
 REGEXP8: REGEXP9 { $$ = $1; }
        | COMPLEMENT REGEXP8 {
-       		// TODO: forbid pair complement (ie ~a:b)
+       		// forbid pair complement (ie ~a:b)
+		if (! $2->is_automaton())
+		{
+		  xreerror("Complement operator ~ is defined only for automata\n"
+		           "Use expression [[?:?] - A]] instead where A is the relation to be complemented.");
+		  YYABORT;
+		}
        		HfstTransducer complement = HfstTransducer::identity_pair( hfst::xre::format );
        		complement.repeat_star().optimize();
        		complement.subtract(*$2).prune_alphabet(false);
diff --git a/man/hfst-reweight-tagger.1 b/man/hfst-reweight-tagger.1
index 51604ed..85160cc 100644
--- a/man/hfst-reweight-tagger.1
+++ b/man/hfst-reweight-tagger.1
@@ -1,7 +1,7 @@
 .\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.47.3.
 .TH HFST-REWEIGHT-TAGGER "1" "March 2017" "HFST" "User Commands"
 .SH NAME
-hfst-reweight-tagger \- =Reweight a tagger accoring to a configuration file
+hfst-reweight-tagger \- =Reweight a tagger according to a configuration file
 .SH SYNOPSIS
 .B hfst-reweight-tagger
 [\fI\,OPTIONS\/\fR...] [\fI\,INFILE\/\fR]
diff --git a/python/Makefile.am b/python/Makefile.am
index daad914..96954d1 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -9,9 +9,9 @@
 
 SUBDIRS = test
 EXTRA_DIST = libhfst.i docstrings.i README setup.py \
-hfst_extensions.cc hfst_file_extensions.cc hfst_lexc_extensions.cc hfst_sfst_extensions.cc \
-hfst_lookup_extensions.cc hfst_pmatch_extensions.cc hfst_prolog_extensions.cc \
-hfst_regex_extensions.cc hfst_rules_extensions.cc hfst_xfst_extensions.cc \
+hfst_extensions.cpp hfst_file_extensions.cpp hfst_lexc_extensions.cpp hfst_sfst_extensions.cpp \
+hfst_lookup_extensions.cpp hfst_pmatch_extensions.cpp hfst_prolog_extensions.cpp \
+hfst_regex_extensions.cpp hfst_rules_extensions.cpp hfst_xfst_extensions.cpp \
 hfst/__init__.py hfst/exceptions/__init__.py hfst/sfst_rules/__init__.py \
 hfst/xerox_rules/__init__.py
 
diff --git a/python/README b/python/README
index 7fba5d2..e0ef3df 100644
--- a/python/README
+++ b/python/README
@@ -1,15 +1,15 @@
 
 This folder contains source code for SWIG bindings for using HFST library with
-Python. The bindings work with Python version 3.
+Python. The bindings work with Python version 2.7 and from version 3.4 upwards.
 
 ============
 REQUIREMENTS
 ============
 
 The requirements for HFST C++ library are given in README of parent directory.
-The setup script has been tested with the following version combinations of
-swig and python: swig2.0.4/python3.2mu and swig3.0/python 3.4m.
-
+Compiling the bindings requires swig (tested with version 3.0.12) and
+distutils (tested with version 36.0.1) as well as a C++ compiler (tested with
+gcc 5.4.0).
 
 =====================
 BUILDING THE BINDINGS
@@ -20,16 +20,14 @@ Once you've successfully built and installed HFST library (located in the
 parent directory, if you are compiling from source), use the script setup.py
 to build the Python extension eg. like so:
 
-    python3 setup.py build_ext --inplace
+    python setup.py build_ext --inplace
 
 If you have only built HFST library but not installed it (or have an earlier
-version of HFST library installed) and want to build the bindings, you either
-have to add full path to ../libhfst/src/.libs to LD_LIBRARY_PATH or hard-code
-the library path by modifying setup.py:
+version of HFST library installed) and want to build the bindings, running
+
+    python setup.py build_ext --inplace --local-hfst
 
-  extra_link_arguments = []
-  # If you wish to link to the local HFST library, replace the above with:
-  # extra_link_arguments = ["-Wl,-rpath=" + absolute_libhfst_src_path + "/.libs"]
+will link to the HFST library located in ../libhfst/src.
 
 
 =================
@@ -46,7 +44,7 @@ INSTALLING THE BINDINGS
 
 If you wish to install the extension, run
 
-    python3 setup.py install
+    python setup.py install
 
 The same that was said about linking to HFST C++ library in 'Building the
 bindings' above, applies also to installing.
@@ -54,8 +52,8 @@ bindings' above, applies also to installing.
 
 For further information, consult
 
-    python3 setup.py --help
-    python3 setup.py --help-commands
+    python setup.py --help
+    python setup.py --help-commands
 
 and the distutils documentation.
 
@@ -117,6 +115,3 @@ If this is the case, run
 
 after build/installation to be able to use HfstException and its subclasses in
 Python.
-
-Python version 3.4 requires swig 3.0, else HFST exception classes will not be
-handled correctly by Python.
diff --git a/python/doc/Doxyfile b/python/doc/Doxyfile
index a1034fe..333eb00 100644
--- a/python/doc/Doxyfile
+++ b/python/doc/Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME           = "HFST - Helsinki Finite-State Transducer Technology - P
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = "version 3.12.2"
+PROJECT_NUMBER         = "version 3.12.3 (under development)"
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
diff --git a/python/doc/hfst/__init__.py b/python/doc/hfst/__init__.py
index 0a24eec..e0ab865 100644
--- a/python/doc/hfst/__init__.py
+++ b/python/doc/hfst/__init__.py
@@ -49,7 +49,7 @@
 #
 # \section download_hfst Download
 #
-#   - <a href="https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstPython">Download and install</a> HFST Python API
+#   - <a href="https://pypi.python.org/pypi/hfst">Download and install</a> HFST Python API
 #
 #
 #\section links Links
@@ -372,6 +372,19 @@ def compile_xfst_file(filename, **kwargs):
 def compile_pmatch_file(filename):
     pass
 
+## Compile twolc file \a inputfilename and store the result to file \a outputfilename.
+# @param inputfilename The name of the twolc input file.
+# @param outputfilename The name of the transducer output file.
+# @param kvargs Arguments recognized are: silent, verbose, resolve_right_conflicts, resolve_left_conflicts, type.
+# @param silent Whether compilation is performed in silent mode, defaults to False.
+# @param verbose Whether compilation is performed in verbose mode, defaults to False.
+# @param resolve_right_conflicts Whether right arrow conflicts are resolved, defaults to True.
+# @param resolve_left_conflicts Whether left arrow conflicts are resolved, defaults to False.
+# @param type` Implementation type of the compiler, defaults to hfst.get_default_fst_type().
+# @return On success zero, else an integer other than zero.
+def compile_twolc_file(inputfilename, outputfilename, **kwargs):
+    pass
+
 ## Compile a pmatch expression into a tuple of transducers.
 # @param expr A string defining how pmatch is done.
 # @see hfst.compile_pmatch_file
@@ -593,6 +606,31 @@ class PrologReader:
     def __next__(self):
         pass
 
+## Return a concatenation of *transducers*.
+# @param transducers An iterable object of transducers.
+def concatenate(transducers):
+    pass
+
+## Return a union of *transducers*.
+# @param transducers An iterable object of transducers.
+def disjunct(transducers):
+    pass
+
+## Return an intersection of *transducers*.
+# @param transducers An iterable object of transducers.
+def intersect(transducers):
+    pass
+
+## Return a composition of *transducers*.
+# @param transducers An iterable object of transducers.
+def compose(transducers):
+    pass
+
+## Return a cross product of *transducers*.
+# @param transducers An iterable object of transducers.
+def cross_product(transducers):
+    pass
+
 ## A simple transducer class with tropical weights.
 #
 #    An example of creating an HfstBasicTransducer [foo:bar baz:baz]
@@ -748,6 +786,8 @@ class HfstBasicTransducer:
     # @param state The number of the state where the transition is added. If it does not exist, it is created.
     # @param transition A hfst.HfstBasicTransition that is added to \a state.
     # @param add_symbols_to_alphabet Whether the transition symbols are added to the alphabet of the transducer. (In special cases this is not wanted.)
+    # @note Adding transitions during iteration (e.g. with #transitions) will invalidate the iteration. Iteration of states (e.g. with #states) is possible.
+    # @see #remove_transition
     def add_transition(self, state, transition, add_symbols_to_alphabet=True):
         pass
 
@@ -757,13 +797,59 @@ class HfstBasicTransducer:
     # @param input The input symbol of the transition.
     # @param output The output symbol of the transition.
     # @param weight The weight of the transition.
+    # @note Adding transitions during iteration (e.g. with #transitions) will invalidate the iteration. Iteration of states (e.g. with #states) is possible.
+    # @see #remove_transition
     def add_transition(self, source, target, input, output, weight=0):
         pass
 
-    ## Remove transition \a transition from state \a s.
+    ## Remove all transitions equivalent to \a transition from state \a s.
     # @param s The state which \a transition belongs to.
-    # @param transition The transition to be removed.
-    # @param remove_symbols_from_alphabet Whether 
+    # @param transition A transition which is compared with all transitions of state \a state, ignoring the weights. It a transition is equivalent to \a transition, it is removed from the transducer.
+    # @param remove_symbols_from_alphabet Remove such symbols from transducer alphabet that no longer occur in its transitions (as a result of transition removal).
+    # @note Removing transitions during iteration (e.g. with #transitions) will invalidate the iteration. Iteration of states (e.g. with #states) is possible.
+    # @see #add_transition
+    #
+    # An example of allowing transition input and output symbols to be swapped with weight 0.5 and stay as they are with weight 0.3:
+    #
+    # \verbatim
+    # X = hfst.regex("a:A | b:B c:C")
+    # B = hfst.HfstBasicTransducer(X)
+    # print(B)
+    #
+    # for state in B.states():
+    #     arcs_to_be_removed=[]
+    #     arcs_to_be_added=[]
+    #     for arc in B.transitions(state):
+    #         tostate = arc.get_target_state()
+    #         insym = arc.get_input_symbol()
+    #         outsym = arc.get_output_symbol()
+    #         arcs_to_be_removed.append(arc)
+    #         arcs_to_be_added.append(hfst.HfstBasicTransition(tostate, insym, outsym, 0.3))
+    #         arcs_to_be_added.append(hfst.HfstBasicTransition(tostate, outsym, insym, 0.5))
+    #     for arc in arcs_to_be_removed:
+    #         B.remove_transition(state, arc)
+    #     for arc in arcs_to_be_added:
+    #         B.add_transition(state, arc)
+    #
+    # print(B)
+    # \endverbatim
+    #
+    # Result:
+    #
+    # \verbatim
+    # 0       1       b       B       0
+    # 0       2       a       A       0
+    # 1       2       c       C       0
+    # 2       0
+    #
+    # 0       1       b       B       0.3
+    # 0       1       B       b       0.5
+    # 0       2       a       A       0.3
+    # 0       2       A       a       0.5
+    # 1       2       c       C       0.3
+    # 1       2       C       c       0.5
+    # 2       0
+    # \endverbatim
     def remove_transition(self, s, transition, remove_symbols_from_alphabet=False):
         pass
     
@@ -932,6 +1018,10 @@ class HfstBasicTransducer:
     # If the state does not exist, it is created.
     def set_final_weight(self, state, weight):
         pass
+
+    ## Remove final weight from state \a state, i.e. make it a non-final state.
+    def remove_final_weight(self, state):
+        pass
     
     ## Sort the arcs of this transducer according to input and output symbols.
     # @return This transducer.
diff --git a/python/docstrings.i b/python/docstrings.i
index 2fc74e0..8f94cda 100644
--- a/python/docstrings.i
+++ b/python/docstrings.i
@@ -426,17 +426,22 @@ final weight is copied to the epsilon transition.
 
 %feature("docstring") hfst::HfstBasicTransducer::remove_transition
 """
-
-Remove transition *transition* from state *s*.
+Remove all transitions equivalent to *transition* from state *s*.
 
 Parameters
 ----------
 * `s` :
     The state which *transition* belongs to.
 * `transition` :
-    The transition to be removed.
+    A transition which is compared with all transitions of state *s*, ignoring
+    the weights. It a transition is equivalent to *transition*, it is removed
+    from the transducer.
 * `remove_symbols_from_alphabet` :
-    (?)
+    Remove such symbols from transducer alphabet that no longer occur in its
+    transitions (as a result of transition removal). Defaults to False.
+
+Note: Removing transitions during iteration (e.g. with 'transitions') will
+invalidate the iteration. Iteration of states (e.g. with 'states') is possible.
 """
 
 %feature("docstring") hfst::HfstBasicTransducer::add_transition
@@ -455,6 +460,9 @@ Parameters
 * `add_symbols_to_alphabet` :
     Whether the transition symbols are added to the alphabet of the transducer.
     (In special cases this is not wanted.)
+
+Note: Adding transitions during iteration (e.g. with 'transitions') will
+invalidate the iteration. Iteration of states (e.g. with 'states') is possible.
 """
 
 %feature("docstring") hfst::HfstBasicTransducer::add_transition
@@ -470,13 +478,16 @@ Parameters
     it is created.
 * `target` :
     The number of the state where the transition leads. If it does not exist, it
-    is created. (?)
+    is created.
 * `input` :
     The input symbol of the transition.
 * `output` :
     The output symbol of the transition.
 * `weight` :
     The weight of the transition.
+
+Note: Adding transitions during iteration (e.g. with 'transitions') will
+invalidate the iteration. Iteration of states (e.g. with 'states') is possible.
 """
 
 %feature("docstring") hfst::HfstBasicTransducer::read_prolog
@@ -585,6 +596,12 @@ Set the final weight of state *state* in this transducer to *weight*.
 If the state does not exist, it is created.
 """
 
+%feature("docstring") hfst::HfstBasicTransducer::remove_final_weight
+"""
+
+Remove the final weight of state *state* in this transducer, i.e. make the state non-final.
+"""
+
 %feature("docstring") hfst::HfstBasicTransducer::add_symbols_to_alphabet
 """
 
diff --git a/python/hfst/__init__.py b/python/hfst/__init__.py
index 1f40ccc..cf86b2f 100644
--- a/python/hfst/__init__.py
+++ b/python/hfst/__init__.py
@@ -47,7 +47,7 @@ CLASSES:
 
 """
 
-__version__ = "3.12.1.0"
+__version__ = "3.13.0.0"
 
 import hfst.exceptions
 import hfst.sfst_rules
@@ -327,7 +327,7 @@ def regex(re, **kvargs):
             vtype = str(type(v))
             if "HfstTransducer" in vtype:
                 comp.define_transducer(k,v)
-                print('defining transducer')
+                # print('defining transducer')
             else:
                 pass
 
@@ -745,7 +745,7 @@ def compile_xfst_file(filename, **kvargs):
        if error == sys.stdout:
           arg2 == "cout"
 
-       retval = hfst_compile_xfst(xfstcomp, data, arg1, arg2)
+       retval = libhfst.hfst_compile_xfst(xfstcomp, data, arg1, arg2)
 
        if isinstance(output, StringIO):
           output.write(unicode(libhfst.get_hfst_xfst_string_one(), 'utf-8'))
@@ -756,6 +756,57 @@ def compile_xfst_file(filename, **kvargs):
       print('Parsed file with return value %i (0 indicating succesful parsing).' % retval)
     return retval
 
+def compile_twolc_file(inputfilename, outputfilename, **kvargs):
+    """
+    Compile twolc file *inputfilename* and store the result to file *outputfilename*.
+
+    Parameters
+    ----------
+    * `inputfilename` :
+        The name of the twolc input file.
+    * `outputfilename` :
+        The name of the transducer output file.
+    * `kvargs` :
+        Arguments recognized are: silent, verbose, resolve_right_conflicts, resolve_left_conflicts, type.
+    * `silent` :
+        Whether compilation is performed in silent mode, defaults to False.
+    * `verbose` :
+        Whether compilation is performed in verbose mode, defaults to False.
+    * `resolve_right_conflicts` :
+        Whether right arrow conflicts are resolved, defaults to True.
+    * `resolve_left_conflicts` :
+        Whether left arrow conflicts are resolved, defaults to False.
+    * `type` :
+        Implementation type of the compiler, defaults to hfst.get_default_fst_type().
+
+    Returns
+    -------
+    On success zero, else an integer other than zero.
+    """
+    silent=False
+    verbose=False
+    resolve_right_conflicts=True
+    resolve_left_conflicts=False
+    implementation_type=get_default_fst_type()
+
+    for k,v in kvargs.items():
+        if k == 'type':
+            implementation_type = v
+        elif k == 'silent':
+            silent=v
+        elif k == 'verbose':
+            verbose=v
+        elif k == 'resolve_right_conflicts':
+            resolve_right_conflicts=v
+        elif k == 'resolve_left_conflicts':
+            resolve_left_conflicts=v
+        else:
+            print('Warning: ignoring unknown argument %s.' % (k))
+
+    return libhfst.TwolcCompiler.compile(inputfilename, outputfilename, silent, verbose,
+                                         resolve_right_conflicts, resolve_left_conflicts,
+                                         implementation_type)
+
 def compile_pmatch_file(filename):
     """
     Compile pmatch expressions as defined in *filename* and return a tuple of
@@ -934,15 +985,27 @@ def fsa(arg):
     deftok = HfstTokenizer()
     retval = HfstBasicTransducer()
     if isinstance(arg, str):
-       retval.disjunct(deftok.tokenize(_check_word(arg)), 0)
+       if len(arg) == 0:
+           retval.set_final_weight(0, 0) # epsilon transducer with zero weight
+       else:
+           retval.disjunct(deftok.tokenize(_check_word(arg)), 0)
     elif _is_weighted_word(arg):
-       retval.disjunct(deftok.tokenize(_check_word(arg[0])), arg[1])
+       if len(arg) == 0:
+           retval.set_final_weight(0, arg[1]) # epsilon transducer with weight
+       else:
+           retval.disjunct(deftok.tokenize(_check_word(arg[0])), arg[1])
     elif isinstance(arg, tuple) or isinstance(arg, list):
        for word in arg:
            if _is_weighted_word(word):
-              retval.disjunct(deftok.tokenize(_check_word(word[0])), word[1])
+              if len(word) == 0:
+                  retval.set_final_weight(0, word[1]) # epsilon transducer with weight
+              else:
+                  retval.disjunct(deftok.tokenize(_check_word(word[0])), word[1])
            elif isinstance(word, str):
-              retval.disjunct(deftok.tokenize(_check_word(word)), 0)
+              if len(word) == 0:
+                  retval.set_final_weight(0, 0) # epsilon transducer with zero weight
+              else:
+                  retval.disjunct(deftok.tokenize(_check_word(word)), 0)
            else:
               raise RuntimeError('Tuple/list element not a string or tuple of string and weight.')
     else:
@@ -1230,6 +1293,34 @@ def intersect(transducers):
     retval.minimize()
     return retval
 
+def compose(transducers):
+    """
+    Return a composition of *transducers*.
+    """
+    retval = None
+    for tr in transducers:
+        if retval == None:
+            retval = HfstTransducer(tr)
+        else:
+            retval.compose(tr)
+    retval.minimize()
+    return retval
+
+def cross_product(transducers):
+    """
+    Return a cross product of *transducers*.
+    """
+    retval = None
+    for tr in transducers:
+        if retval == None:
+            retval = HfstTransducer(tr)
+        else:
+            retval.cross_product(tr)
+    retval.minimize()
+    return retval
+
+
+
 class ImplementationType:
     """
     Back-end implementation.
diff --git a/python/hfst_extensions.cc b/python/hfst_extensions.cpp
similarity index 100%
rename from python/hfst_extensions.cc
rename to python/hfst_extensions.cpp
diff --git a/python/hfst_file_extensions.cc b/python/hfst_file_extensions.cpp
similarity index 100%
rename from python/hfst_file_extensions.cc
rename to python/hfst_file_extensions.cpp
diff --git a/python/hfst_lexc_extensions.cc b/python/hfst_lexc_extensions.cpp
similarity index 100%
rename from python/hfst_lexc_extensions.cc
rename to python/hfst_lexc_extensions.cpp
diff --git a/python/hfst_lookup_extensions.cc b/python/hfst_lookup_extensions.cpp
similarity index 100%
rename from python/hfst_lookup_extensions.cc
rename to python/hfst_lookup_extensions.cpp
diff --git a/python/hfst_pmatch_extensions.cc b/python/hfst_pmatch_extensions.cpp
similarity index 100%
rename from python/hfst_pmatch_extensions.cc
rename to python/hfst_pmatch_extensions.cpp
diff --git a/python/hfst_prolog_extensions.cc b/python/hfst_prolog_extensions.cpp
similarity index 100%
rename from python/hfst_prolog_extensions.cc
rename to python/hfst_prolog_extensions.cpp
diff --git a/python/hfst_regex_extensions.cc b/python/hfst_regex_extensions.cpp
similarity index 100%
rename from python/hfst_regex_extensions.cc
rename to python/hfst_regex_extensions.cpp
diff --git a/python/hfst_rules_extensions.cc b/python/hfst_rules_extensions.cpp
similarity index 100%
rename from python/hfst_rules_extensions.cc
rename to python/hfst_rules_extensions.cpp
diff --git a/python/hfst_sfst_extensions.cc b/python/hfst_sfst_extensions.cpp
similarity index 100%
rename from python/hfst_sfst_extensions.cc
rename to python/hfst_sfst_extensions.cpp
diff --git a/python/hfst_xfst_extensions.cc b/python/hfst_xfst_extensions.cpp
similarity index 100%
rename from python/hfst_xfst_extensions.cc
rename to python/hfst_xfst_extensions.cpp
diff --git a/python/libhfst.i b/python/libhfst.i
index ad01b99..c406b26 100644
--- a/python/libhfst.i
+++ b/python/libhfst.i
@@ -46,18 +46,19 @@
 #include "implementations/HfstBasicTransition.h"
 #include "implementations/HfstBasicTransducer.h"
 #include "implementations/optimized-lookup/pmatch.h"
+#include "parsers/TwolcCompiler.h"
 namespace hfst { typedef std::vector<hfst::xeroxRules::Rule> HfstRuleVector; }
 
 // Most of C++ extension code is located in separate files.
-#include "hfst_regex_extensions.cc"
-#include "hfst_extensions.cc"
-#include "hfst_lexc_extensions.cc"
-#include "hfst_xfst_extensions.cc"
-#include "hfst_pmatch_extensions.cc"
-#include "hfst_sfst_extensions.cc"
-#include "hfst_lookup_extensions.cc"
-#include "hfst_rules_extensions.cc"
-#include "hfst_prolog_extensions.cc"
+#include "hfst_regex_extensions.cpp"
+#include "hfst_extensions.cpp"
+#include "hfst_lexc_extensions.cpp"
+#include "hfst_xfst_extensions.cpp"
+#include "hfst_pmatch_extensions.cpp"
+#include "hfst_sfst_extensions.cpp"
+#include "hfst_lookup_extensions.cpp"
+#include "hfst_rules_extensions.cpp"
+#include "hfst_prolog_extensions.cpp"
 %}
 
 #ifdef _MSC_VER
@@ -1113,6 +1114,7 @@ class HfstBasicTransducer {
     bool is_final_state(HfstState s) const;
     float get_final_weight(HfstState s) const throw(StateIsNotFinalException, StateIndexOutOfBoundsException);
     void set_final_weight(HfstState s, const float & weight);
+    void remove_final_weight(HfstState s);
 %rename("_transitions") transitions(HfstState s);
     hfst::implementations::HfstBasicTransitions & transitions(HfstState s);
     bool is_infinitely_ambiguous();
@@ -1591,6 +1593,18 @@ namespace hfst_rules {
 
 } // namespace hfst
 
+namespace hfst {
+  namespace twolc {
+    class TwolcCompiler
+    {
+    public:
+      static int compile(const std::string & inputfile, const std::string & outputfile,
+			 bool silent, bool verbose, bool resolve_left_conflicts,
+			 bool resolve_right_conflicts, hfst::ImplementationType type);
+    };
+  }
+}
+
 // *** PmatchContainer *** //
 
 namespace hfst_ol {
diff --git a/python/pypi/MANIFEST.in b/python/pypi/MANIFEST.in
index 1860c4e..9c482bd 100644
--- a/python/pypi/MANIFEST.in
+++ b/python/pypi/MANIFEST.in
@@ -1,13 +1,13 @@
-include hfst_extensions.cc
-include hfst_file_extensions.cc
-include hfst_lexc_extensions.cc
-include hfst_lookup_extensions.cc
-include hfst_pmatch_extensions.cc
-include hfst_prolog_extensions.cc
-include hfst_regex_extensions.cc
-include hfst_rules_extensions.cc
-include hfst_xfst_extensions.cc
-include hfst_sfst_extensions.cc
+include hfst_extensions.cpp
+include hfst_file_extensions.cpp
+include hfst_lexc_extensions.cpp
+include hfst_lookup_extensions.cpp
+include hfst_pmatch_extensions.cpp
+include hfst_prolog_extensions.cpp
+include hfst_regex_extensions.cpp
+include hfst_rules_extensions.cpp
+include hfst_xfst_extensions.cpp
+include hfst_sfst_extensions.cpp
 include docstrings.i
 include libhfst/src/*.h
 include libhfst/src/implementations/*.h
@@ -15,6 +15,11 @@ include libhfst/src/implementations/optimized-lookup/*.h
 include libhfst/src/implementations/compose_intersect/*.h
 include libhfst/src/parsers/*.h
 include libhfst/src/parsers/*.hh
+include libhfst/src/parsers/alphabet_src/*.h
+include libhfst/src/parsers/io_src/*.h
+include libhfst/src/parsers/rule_src/*.h
+include libhfst/src/parsers/string_src/*.h
+include libhfst/src/parsers/variable_src/*.h
 include back-ends/foma/*.h
 include back-ends/openfst/src/include/fst/*.h
 include config.h
diff --git a/python/pypi/README.rst b/python/pypi/README.rst
index bef326f..87cd47c 100644
--- a/python/pypi/README.rst
+++ b/python/pypi/README.rst
@@ -12,50 +12,82 @@ morphological complexity.
 Requirements
 ############
 
-The bindings have been tested with python3. Wheels are offered only for python
-version 3.4 and higher for Windows and Mac OS X. For Linux users, we recommend
-using the `Debian packages
-<https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstPython#Option_1_Installing_the_debian_p>`_.
-
-We currently offer only 64-bit wheels for Windows. They also require a 64-bit
+For Windows and Mac OS X, we offer binary wheels on PyPI. Wheels are available
+for python versions 2.7, 3.4, 3.5 and 3.6.
+The wheels for Windows are 32-bit; they also require a 32-bit
 python to work correctly. Wheels for Mac are compiled as universal binaries
-that work on both 32- and 64-bit environments. OS X must be 10.7 or higher.
-
-Compiling from source requires at least swig (tested with versions 2.0.4 and
-3.0.5), a C++ compiler (tested with gcc 4.6.3, clang x.y.z and Visual C++ 10.0
-for python 3.4 and 14.0 for python >= 3.5), and python3 with setuptools
-(tested with version 28.8.0). All these must be located on directories listed
-on system PATH. On Linux and Mac OS X, readline and getline libraries must be
-available and the C++ compiler must support flag 'std=c++0x'. A known issue
-on OS X is that compiling C code fails as flag 'std=c++0x' must be set
-globally in setup.py but is not accepted when the source is pure C.
-
-Installation
-############
+that work both on 32- and 64-bit environments. OS X must be 10.6 or higher.
+
+For Linux, we offer only the source code on PyPI. It is also possible to install hfst
+using Debian binary packages. This is the recommended way if the environment supports Debian.
+Compiling hfst from source requires a C++ compiler (tested with gcc 5.4.0),
+readline and getline libraries for C++ compiler and setuptools package for python
+(tested with version 28.8.0). Swig is no longer needed as pre-generated files are
+included in source distribution.
+
+Installation via PyPI
+#####################
 
-We recommend using ``pip`` tool for installation. For python version 3, it is
-usually named ``pip3`` (plain ``pip`` being used for python version 2).
-Starting from python 3.4, pip is included by default and can be called with
-``python3 -m pip``.
+We recommend using ``pip`` tool for installation for Windows and OS X.
+``pip`` also works for Linux, but everything will be compiled from
+source. Before installation, see that dependencies given under heading 'Requirements' are met.
 
-Basic installation with ``pip3`` on command line:
+For python version 3, the ``pip`` tool is usually named ``pip3``, plain ``pip`` being used
+for python version 2. Basic installation is done with:
 
 ``pip3 install [--upgrade] hfst``
 
-or, starting from python version 3.4, directly via python:
+``pip install [--upgrade] hfst``
+
+Starting from python 3.4.0 and 2.7.9, pip is included by default
+and can be called via python with option ``-m pip``:
 
 ``python3 -m pip install [--upgrade] hfst``
 
+``python -m pip install [--upgrade] hfst``
+
 The commands above are run in a shell/terminal/command prompt, but they can
-also be run on python command line or via a graphical user interface 
-(e.g. IDLE) with pip.main that takes arguments in a list:
+also be run on python command line or via a graphical user interface
+(e.g. IDLE) with ``pip.main`` that takes arguments in a list:
 
 | ``import pip``
 | ``pip.main(['install','--upgrade','hfst'])``
 
+The option ``--upgrade`` makes sure that the newest version of hfst will be installed
+replacing any earlier versions installed. The option ``--verbose``
+will show what happens during the installation process. This can be useful when compiling from source.
+
+Installation for Linux using Debian packages
+############################################
+
+Fetch newest Debian release (named ``python3-libhfst`` for python version 3 and ``python-libhfst`` for python version 2)
+from `Apertium <http://apertium.projectjj.com/apt/nightly/pool/main/h/hfst/>`_ and install it with
+
+``dpkg --install  python[3]-libhfst_***.deb``
+
+When choosing the right package, the command ``lsb_release -a`` might be helpful.
+It will e.g. print something like
+
+| ``No LSB modules are available.``
+| ``Distributor ID: Ubuntu``
+| ``Description:    Ubuntu 16.04.2 LTS``
+| ``Release:        16.04``
+| ``Codename:       xenial``
+
+In the example case, the line Codename shows that the right package is of form ``*~xenial1_*.deb``.
+
+The command ``file /usr/bin/file`` is one way to check whether your system is 64-bit or 32-bit. It will print something like:
+
+``/usr/bin/file: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked ...``
+
+In the case above, a package ending in ``amd64.deb`` is the right choice.
 
-Alternative `installation instructions <https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstPython>`_
-are given on our KitWiki pages.
+Compiling from scratch
+######################
+
+It is also possible to compile HFST C++ library and the python bindings from scratch.
+Clone or download our `Github repository <https://github.com/hfst/hfst>`_ and
+see `README <https://github.com/hfst/hfst/tree/master/python>`_ of the ``python`` subdirectory.
 
 Documentation
 #############
@@ -76,10 +108,20 @@ HFST is licensed under Gnu GPL version 3.0.
 Troubleshooting
 ###############
 
+(In the commands below, ``python[3]`` means either ``python`` or ``python3`` depending of the version of python you are using;
+the same goes for ``pip[3]`` meaning ``pip`` or ``pip3``.)
+
 *Pip starts to compile from source although there is a wheel available:*
 
-Try upgrading pip with ``pip3 install --upgrade pip`` or 
-``python3 -m pip install --upgrade pip``. Another reason for this can be that
+Try upgrading pip with
+
+``pip[3] install --upgrade pip``
+
+or
+
+``python[3] -m pip install --upgrade pip``.
+
+Another reason for this can be that
 the source package on PyPI is newer (i.e. has a higher version number) than
 the corresponding wheel for the given environment. Report this via our
 `issue tracker <https://github.com/hfst/hfst/issues/>`_ so a fresh wheel
@@ -88,22 +130,29 @@ will be created.
 *Error message "command ... failed with error code ...":*
 
 Try rerunning pip in verbose mode with
-``pip3 install --verbose [--upgrade] hfst`` to get more information.
+
+``pip[3] install --verbose [--upgrade] hfst``
+
+or
+
+``python[3] -m pip install --verbose [--upgrade] hfst``
+
+to get more information.
 
 *Error message "error: could not delete ... : permission denied":*
 
 You do not have sufficient rights to install packages. On Mac and Linux, try
-installing as super user with ``sudo pip3 install [--upgrade] hfst``.
+installing as super user with
+
+``sudo pip[3] install [--upgrade] hfst``
+
+or
+
+``sudo python[3] -m pip install [--upgrade] hfst``.
+
 On Windows, reopen Command Prompt/Python command line/IDLE by right-clicking
 and choose "Run as administrator", then run pip again.
 
-*Using flag -std=c++0x causes an error in the C++/C compiler:*
-
-This is a known issue on OS X when compiling from source. The flag must be
-set globally in setup.py but is not accepted when the source is pure C, as
-some of our back-end files are. If there isn't a wheel available for your
-environment, see alternative 
-`installation instructions <https://kitwiki.csc.fi/twiki/bin/view/KitWiki/HfstPython>`_.
 
 Links
 #####
diff --git a/python/pypi/copy-files-win.sh b/python/pypi/copy-files-win.sh
new file mode 100755
index 0000000..6162ad0
--- /dev/null
+++ b/python/pypi/copy-files-win.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+if [ "$1" = "--help" -o "$1" = "-h" ]; then
+    echo "copy-files.sh [--with-c-foma]"
+    echo ""
+    echo "Copy files needed for pypi distribution on Windows."
+    echo ""
+    echo "--with-c-foma:   copy the C version of foma backend (instead oc C++)"
+    echo ""
+    echo "NOTE: flex/bison-generated cc and hh files are copied as such to"
+    echo "avoid dependency on swig. Make sure you have a fresh version of them"
+    echo "(run 'compile-cc-files-win.sh' in '../../libhfst/src/parsers', if needed)."
+    echo ""
+    exit 0
+fi
+
+CPP_FOMA="true"
+if [ "$1" = "--with-c-foma" ]; then
+    CPP_FOMA="false"
+fi
+
+if ! [ -d "back-ends" ]; then mkdir back-ends; fi
+if ! [ -d "libhfst" ]; then mkdir libhfst; fi
+if ! [ -d "hfst" ]; then mkdir hfst; fi
+if ! [ -d "test" ]; then mkdir test; fi
+
+cp -R ../../back-ends/* back-ends/
+cp -R ../../libhfst/* libhfst/
+cp -R ../hfst/* hfst/
+cp -R ../test/* test/
+
+# files under ../
+for file in hfst_extensions.cpp hfst_file_extensions.cpp hfst_lexc_extensions.cpp \
+hfst_lookup_extensions.cpp hfst_pmatch_extensions.cpp hfst_prolog_extensions.cpp \
+hfst_regex_extensions.cpp hfst_rules_extensions.cpp hfst_xfst_extensions.cpp \
+hfst_sfst_extensions.cpp libhfst.i docstrings.i ;
+do
+    cp ../$file $file
+done
+
+# Copy all files that have a c++ version as backend files to be compiled.
+if [ "$CPP_FOMA" = "true" ]; then
+    cp back-ends/foma/cpp-version/* back-ends/foma/
+fi
+
+# .cc -> .cpp
+for dir in back-ends libhfst;
+do
+    find $dir -name "*.cc" | sed 's/\(.*\).cc/mv \1.cc \1.cpp/' | sh
+done
+
+# unistd.h -> io.h
+for file in xfst-lexer htwolcpre1-lexer htwolcpre2-lexer htwolcpre3-lexer sfst-scanner pmatch_lex lexc-lexer xre_lex;
+do
+    sed -i 's/#include <unistd.h>/#include <io.h>/' libhfst/src/parsers/$file.cpp
+done
+for file in lex.cmatrix.cpp lex.yy.cpp;
+do
+    sed -i 's/#include <unistd.h>/#include <io.h>/' back-ends/foma/$file
+done
+
+# h.*wrap( ) -> h.*wrap(void)
+sed -i 's/hxfstwrap( )/hxfstwrap(void)/' libhfst/src/parsers/xfst-lexer.cpp
+sed -i 's/pmatchwrap( )/pmatchwrap(void)/' libhfst/src/parsers/pmatch_lex.cpp
+sed -i 's/hlexcwrap( )/hlexcwrap(void)/' libhfst/src/parsers/lexc-lexer.cpp
+
+# copy windows-scpecific headers
+cp ../../scripts/windows/stdint.h back-ends/foma/stdint.h
+cp ../../scripts/windows/inttypes.h back-ends/foma/inttypes.h
diff --git a/python/pypi/copy-files.sh b/python/pypi/copy-files.sh
index b2e3428..967f512 100755
--- a/python/pypi/copy-files.sh
+++ b/python/pypi/copy-files.sh
@@ -1,5 +1,27 @@
 #!/bin/sh
 
+## Copy files needed for a pypi distribution for linux or os x.
+## copy-files-win.sh is the equivalent script for windows environment.
+
+if [ "$1" = "--help" -o "$1" = "-h" ]; then
+    echo "copy-files.sh [--with-c-foma]"
+    echo ""
+    echo "Copy files needed for a pypi distribution on linux and OS X."
+    echo ""
+    echo "--with-c-foma:   copy the C version of foma backend (instead of C++)"
+    echo ""
+    echo "NOTE: flex/bison-generated cc and hh files are copied as such to"
+    echo "avoid dependency on swig. Make sure you have a fresh version of them"
+    echo "(run 'make' in top directory, if needed)."
+    echo ""
+    exit 0
+fi
+
+CPP_FOMA="true"
+if [ "$1" = "--with-c-foma" ]; then
+    CPP_FOMA="false"
+fi
+
 if ! [ -d "back-ends" ]; then mkdir back-ends; fi
 if ! [ -d "libhfst" ]; then mkdir libhfst; fi
 if ! [ -d "hfst" ]; then mkdir hfst; fi
@@ -8,10 +30,21 @@ cp -R ../../back-ends/* back-ends/
 cp -R ../../libhfst/* libhfst/
 cp -R ../hfst/* hfst/
 
-for file in hfst_extensions.cc hfst_file_extensions.cc hfst_lexc_extensions.cc \
-hfst_lookup_extensions.cc hfst_pmatch_extensions.cc hfst_prolog_extensions.cc \
-hfst_regex_extensions.cc hfst_rules_extensions.cc hfst_xfst_extensions.cc \
-hfst_sfst_extensions.cc libhfst.i docstrings.i ;
+for file in hfst_extensions.cpp hfst_file_extensions.cpp hfst_lexc_extensions.cpp \
+hfst_lookup_extensions.cpp hfst_pmatch_extensions.cpp hfst_prolog_extensions.cpp \
+hfst_regex_extensions.cpp hfst_rules_extensions.cpp hfst_xfst_extensions.cpp \
+hfst_sfst_extensions.cpp libhfst.i docstrings.i ;
 do
     cp ../$file $file
 done
+
+# Copy all files that have a c++ version as backend files to be compiled.
+if [ "$CPP_FOMA" = "true" ]; then
+    cp back-ends/foma/cpp-version/* back-ends/foma/
+fi
+
+# .cc -> .cpp
+for dir in back-ends libhfst;
+do
+    find $dir -name "*.cc" | sed 's/\(.*\).cc/mv \1.cc \1.cpp/' | sh
+done
diff --git a/python/pypi/setup.py b/python/pypi/setup.py
index 1abf673..bf886d2 100644
--- a/python/pypi/setup.py
+++ b/python/pypi/setup.py
@@ -4,53 +4,109 @@
 Setup for creating PIP packages for HFST Python bindings.
 
 Before running setup, recursively copy directories 'libhfst/src'
-and 'back-ends' from HFST c++ source code under the directory where
-setup is run. Make sure that the following c++ and header files 
-from 'libhfst/src/parsers' have been generated from flex/yacc
-files before copying:
+and 'back-ends' from HFST C++ source code under the directory where
+setup is run (on linux and OS X with copy-files.sh and on windows with
+copy-files-win.sh). Make sure that the following C++ files 
+from 'libhfst/src/parsers' have been generated from flex/yacc files
+before copying (on linux and OS X by running 'make' and on windows
+with 'compile-parsers-win.sh' located in 'libhfst/src/parsers'):
 
-  lexc-parser.cc pmatch_parse.cc xfst-parser.cc xre_parse.cc
-  lexc-parser.hh pmatch_parse.hh xfst-parser.hh xre_parse.hh
+  lexc-lexer.cc pmatch_lex.cc xfst-lexer.cc xre_lex.cc sfst-scanner.cc
+  lexc-parser.cc pmatch_parse.cc xfst-parser.cc xre_parse.cc sfst-compiler.cc
+  lexc-parser.hh pmatch_parse.hh xfst-parser.hh xre_parse.hh sfst-compiler.hh
 
-Compiling the extensions requires python, swig and a c++ compiler, 
-all located on a directory listed on system PATH. On linux and mac 
-osx, readline and getline must be available and the c++ compiler
-must support flag 'std=c++11'.
+Compiling the extensions requires python, swig and a C++ compiler,
+all located on a directory listed on system PATH. On linux and OS X,
+readline and getline must be available.
 
-The setup script has been tested on linux with gcc 4.6.3, swig 3.0.12 and
-python 3.4 and on windows with msvc 10.0 and swig 3.0.5 (with python 3.3.
-and 3.4) and with msvc 14.0 (with python 3.5 and 3.6).
+The setup script has been tested on linux with gcc 5.4.0, swig 3.0.12 and
+python 3.5 and on windows with swig 3.0.5 and msvc 10.0 (with python 3.4)
+and msvc 14.0 (with python 3.5 and 3.6).
 
 """
 
 from setuptools import setup, Extension
+from sys import argv, platform
 
-from sys import platform
-if platform == "darwin":
-    import os
-    os.environ["_PYTHON_HOST_PLATFORM"] = 'macosx-10.7-x86_64'
+
+# ----- README -----
 
 def readme():
     with open('README.rst') as f:
         return f.read()
 
+
+# ----- SETUP OPTION HANDLING -----
+
+# If hfst-specific option is found in sys.argv, remove it and return True. Else, return False.
+def hfst_specific_option(option):
+    if option in argv:
+        index = argv.index(option)
+        argv.pop(index)
+        return True
+    else:
+        return False
+
+
+# ----- C++ STANDARD  -----
+
+# Use C++ standard C++11 unless compiling for Python 2.7 for Windows (requires msvc 2008 which does not support C++11)
+# or for OS X (C++11 requires libc++ instead of libstdc++ and minimum version requirement 10.7 instead of 10.6).
+CPP_STD_11=True
+from sys import version_info
+if (platform == "darwin") or (platform == "win32" and version_info[0] == 2):
+    CPP_STD_11=False
+# Override default behaviour, if requested.
+if hfst_specific_option('--with-c++11'):
+    CPP_STD_11=True
+if hfst_specific_option('--without-c++11'):
+    CPP_STD_11=False
+
+# By default, use the C++ version of foma backend. C++11 requires option -std=c++0x to be set for C/C++ compiler
+# (this cannot de defined for each file separately) and some compilers refuse to compile C with that option.
+CPP_FOMA=True
+if hfst_specific_option('--with-c++-foma'):
+    CPP_FOMA=True
+if hfst_specific_option('--with-c-foma'):
+    CPP_FOMA=False
+
+# Experimental...
+if platform == "darwin" and CPP_STD_11:
+    import os
+    os.environ["_PYTHON_HOST_PLATFORM"] = 'macosx-10.7-x86_64'
+
+
+# ----- SWIG CONFIGURATION -----
+
 # HFST C++ headers needed by swig when creating the python/c++ interface
 swig_include_dir = "libhfst/src/"
-
+# Generate wrapper for C++
 ext_swig_opts = ["-c++", "-I" + swig_include_dir, "-Wall"]
-import sys
 # for python3.3 and python3.4 on windows, add SDK include directory
-if platform == "win32" and sys.version_info[0] == 3 and (sys.version_info[1] == 3 or sys.version_info[1] == 4):
+if platform == "win32" and version_info[0] == 3 and (version_info[1] == 3 or version_info[1] == 4):
     ext_swig_opts.extend(["-IC:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\Include"])
+# By default, we have a pre-swig-generated wrapper
+ext_source = ["libhfst_wrap.cpp"]
+if hfst_specific_option('--generate-wrapper'):
+    ext_source = ["libhfst.i"]
 
-# readline is needed for hfst.start_xfst(), on windows the shell where HFST
-# python bindings are run from has its own readline which will do
-ext_extra_link_args = []
+# ----- LINKER ARGUMENTS -----
+
+# Readline is needed for hfst.start_xfst(). On windows the shell where HFST
+# python bindings are run from has its own readline which will do.
+include_readline_and_getline=False
 if platform == "linux" or platform == "linux2" or platform == "darwin":
+    include_readline_and_getline=True
+ext_extra_link_args = []
+if include_readline_and_getline:
     ext_extra_link_args = ['-lreadline']
-if platform == "darwin":
+# Experimental...
+if platform == "darwin" and CPP_STD_11:
     ext_extra_link_args.extend(['-mmacosx-version-min=10.7'])
 
+
+# ----- INCLUDE DIRECTORIES -----
+
 # HFST headers needed when compiling the actual c++ extension
 ext_include_dirs = [".", "libhfst/src/", "back-ends/foma", "back-ends",
                     "parsers", "libhfst/src/parsers"]
@@ -59,40 +115,74 @@ if platform == "win32":
 else:
     ext_include_dirs.append("back-ends/openfst/src/include")
 
-# this replaces ./configure
-ext_define_macros = [ ('HAVE_FOMA', None), ('HAVE_OPENFST', None),
-                      ('HAVE_OPENFST_LOG', None) ]
-if platform == "linux" or platform == "linux2" or platform == "darwin":
+
+# ----- CONFIGURATION -----
+
+# Include foma implementation for OS X only when c++11 is disabled.
+include_foma_backend=True
+if platform == "linux" or platform == "linux2" or platform == "win32" or (platform == "darwin" and not CPP_STD_11):
+    include_foma_backend=True
+ext_define_macros = []
+if include_foma_backend:
+    ext_define_macros.append(('HAVE_FOMA', None))
+
+# Openfst backend is always enabled
+ext_define_macros.append(('HAVE_OPENFST', None))
+ext_define_macros.append(('HAVE_OPENFST_LOG', None))
+
+if include_readline_and_getline:
     ext_define_macros.append(('HAVE_READLINE', None))
     ext_define_macros.append(('HAVE_GETLINE', None))
+
+# msvc-specific macros.
 if platform == "win32":
     # MSC_VER_ should already be defined
     for macro in ["HFSTEXPORT", "OPENFSTEXPORT", "WINDOWS", "WIN32", "_CRT_SECURE_NO_WARNINGS"]:
         ext_define_macros.append((macro, None))
 
-# use c++0x standard, if possible
+# If C++11 is not supported, what features will be disabled and where unordered map and set are found.
+if (not CPP_STD_11):
+    # Disable c++11 features.
+    ext_define_macros.append(('NO_CPLUSPLUS_11', None))
+    # Unordered containers are in namespace std::tr1.
+    ext_define_macros.append(('USE_TR1_UNORDERED_MAP_AND_SET', None))
+    # On windows, the header files are not located in directory tr1
+    # although the namespace is std::tr1.
+    if not platform == "win32":
+        ext_define_macros.append(('INCLUDE_TR1_UNORDERED_MAP_AND_SET', None))
+
+
+# ----- COMPILATION OPTIONS -----
+
 ext_extra_compile_args = []
 if platform == "linux" or platform == "linux2" or platform == "darwin":
-    ext_extra_compile_args = ["-std=c++0x", "-Wno-sign-compare", "-Wno-strict-prototypes"]
-if platform == "darwin":
+    ext_extra_compile_args = ["-Wno-sign-compare", "-Wno-strict-prototypes"]
+    # C++11 standard does not need to be specifically requested for msvc compilers.
+    if CPP_STD_11:
+        ext_extra_compile_args.extend(["-std=c++0x"])
+# Experimental...
+if platform == "darwin" and CPP_STD_11:
     ext_extra_compile_args.extend(["-stdlib=libc++", "-mmacosx-version-min=10.7"])
 # define error handling mechanism on windows
 if platform == "win32":
     ext_extra_compile_args = ["/EHsc"]
 
-ext_library_dirs = []
-ext_libraries = []
 
-# on windows, c++ source files have 'cpp' extension
-cpp = ".cc"
-if platform == "win32":
-    cpp = ".cpp"
+# ----- C++ SOURCE FILES -----
+
+# C++ source files have 'cpp' extension
+cpp = ".cpp"
 
 # on windows, openfst back-end is in directory 'openfstwin'
 openfstdir = "openfst"
 if platform == "win32":
     openfstdir = "openfstwin"
 
+# foma source file extension (C++ by default)
+fe = cpp
+if not CPP_FOMA:
+    fe = ".c"
+
 # all c++ extension source files
 libhfst_source_files = ["libhfst/src/parsers/XfstCompiler" + cpp,
                         "libhfst/src/HfstApply" + cpp,
@@ -157,31 +247,56 @@ libhfst_source_files = ["libhfst/src/parsers/XfstCompiler" + cpp,
                         "libhfst/src/parsers/SfstCompiler" + cpp,
                         "libhfst/src/parsers/SfstAlphabet" + cpp,
                         "libhfst/src/parsers/SfstBasic" + cpp,
-                        "libhfst/src/parsers/SfstUtf8" + cpp ]
-
-foma_source_files = [ "back-ends/foma/int_stack.c",
-                      "back-ends/foma/define.c",
-                      "back-ends/foma/determinize.c",
-                      "back-ends/foma/apply.c",
-                      "back-ends/foma/rewrite.c",
-                      "back-ends/foma/topsort.c",
-                      "back-ends/foma/flags.c",
-                      "back-ends/foma/minimize.c",
-                      "back-ends/foma/reverse.c",
-                      "back-ends/foma/extract.c",
-                      "back-ends/foma/sigma.c",
-                      "back-ends/foma/structures.c",
-                      "back-ends/foma/constructions.c",
-                      "back-ends/foma/coaccessible.c",
-                      "back-ends/foma/io.c",
-                      "back-ends/foma/utf8.c",
-                      "back-ends/foma/spelling.c",
-                      "back-ends/foma/dynarray.c",
-                      "back-ends/foma/mem.c",
-                      "back-ends/foma/stringhash.c",
-                      "back-ends/foma/trie.c",
-                      "back-ends/foma/lex.yy.c",
-                      "back-ends/foma/regex.c" ]
+                        "libhfst/src/parsers/SfstUtf8" + cpp,
+                        "libhfst/src/parsers/htwolcpre1-lexer" + cpp,
+                        "libhfst/src/parsers/htwolcpre2-lexer" + cpp,
+                        "libhfst/src/parsers/htwolcpre3-lexer" + cpp,
+                        "libhfst/src/parsers/htwolcpre1-parser" + cpp,
+                        "libhfst/src/parsers/htwolcpre2-parser" + cpp,
+                        "libhfst/src/parsers/htwolcpre3-parser" + cpp,
+                        "libhfst/src/parsers/TwolcCompiler" + cpp,
+                        "libhfst/src/parsers/io_src/InputReader" + cpp,
+                        "libhfst/src/parsers/string_src/string_manipulation" + cpp,
+                        "libhfst/src/parsers/variable_src/RuleSymbolVector" + cpp,
+                        "libhfst/src/parsers/variable_src/RuleVariables" + cpp,
+                        "libhfst/src/parsers/variable_src/RuleVariablesConstIterator" + cpp,
+                        "libhfst/src/parsers/variable_src/VariableValues" + cpp,
+                        "libhfst/src/parsers/rule_src/ConflictResolvingLeftArrowRule" + cpp,
+                        "libhfst/src/parsers/rule_src/ConflictResolvingRightArrowRule" + cpp,
+                        "libhfst/src/parsers/rule_src/LeftArrowRule" + cpp,
+                        "libhfst/src/parsers/rule_src/LeftArrowRuleContainer" + cpp,
+                        "libhfst/src/parsers/rule_src/LeftRestrictionArrowRule" + cpp,
+                        "libhfst/src/parsers/rule_src/OtherSymbolTransducer" + cpp,
+                        "libhfst/src/parsers/rule_src/RightArrowRule" + cpp,
+                        "libhfst/src/parsers/rule_src/RightArrowRuleContainer" + cpp,
+                        "libhfst/src/parsers/rule_src/Rule" + cpp,
+                        "libhfst/src/parsers/rule_src/RuleContainer" + cpp,
+                        "libhfst/src/parsers/rule_src/TwolCGrammar" + cpp,
+                        "libhfst/src/parsers/alphabet_src/Alphabet" + cpp ]
+
+foma_source_files = [ "back-ends/foma/int_stack" + fe,
+                      "back-ends/foma/define" + fe,
+                      "back-ends/foma/determinize" + fe,
+                      "back-ends/foma/apply" + fe,
+                      "back-ends/foma/rewrite" + fe,
+                      "back-ends/foma/topsort" + fe,
+                      "back-ends/foma/flags" + fe,
+                      "back-ends/foma/minimize" + fe,
+                      "back-ends/foma/reverse" + fe,
+                      "back-ends/foma/extract" + fe,
+                      "back-ends/foma/sigma" + fe,
+                      "back-ends/foma/structures" + fe,
+                      "back-ends/foma/constructions" + fe,
+                      "back-ends/foma/coaccessible" + fe,
+                      "back-ends/foma/io" + fe,
+                      "back-ends/foma/utf8" + fe,
+                      "back-ends/foma/spelling" + fe,
+                      "back-ends/foma/dynarray" + fe,
+                      "back-ends/foma/mem" + fe,
+                      "back-ends/foma/stringhash" + fe,
+                      "back-ends/foma/trie" + fe,
+                      "back-ends/foma/lex.yy" + fe,
+                      "back-ends/foma/regex" + fe ]
 
 openfst_source_files =  [ "back-ends/" + openfstdir + "/src/lib/compat" + cpp,
                           "back-ends/" + openfstdir + "/src/lib/flags" + cpp,
@@ -193,34 +308,42 @@ openfst_source_files =  [ "back-ends/" + openfstdir + "/src/lib/compat" + cpp,
 
 libhfst_source_files = libhfst_source_files + openfst_source_files
 
-if platform == "linux" or platform == "linux2" or platform == "win32":
+if include_foma_backend:
     libhfst_source_files = libhfst_source_files + foma_source_files
 
-# clang doesn't accept "-std=c++11" flag when compiling C,
-# so foma back-end must be compiled separately
-# it seems that subprocess doesn't work, so you must compile them manually before running setup.py:
+ext_package_data = {}
+if (platform == "win32"):
+    if (version_info[0] == 2 and version_info[1] > 6):
+        package_data = {'hfst': ['MSVCP90.DLL', 'MSVCR90.DLL']}
+    elif (version_info[0] == 3 and version_info[1] > 4):
+        package_data = {'hfst': ['MSVCP140.DLL', 'VCRUNTIME140.DLL']}
+    else:
+        pass
+
+# (Is this needed?)
+# foma_object_files = []
+# (compile foma backend separately)
 # for file in back-ends/foma/*.c; do clang -fPIC -std=c99 -arch i386 -arch x86_64 -mmacosx-version-min=10.7 -DHAVE_FOMA -c $file ; done
-foma_object_files = []
-if platform == "darwin":
-    for file in foma_source_files:
-        foma_object_files.append(file.replace('back-ends/foma/','').replace('.c','.o'))
+# if platform == "darwin":
+#     for file in foma_source_files:
+#         foma_object_files.append(file.replace('back-ends/foma/','').replace('.c','.o'))
+# in Extension: extra_objects = foma_object_files
+
+
+# ----- The HFST C++ EXTENSION -----
 
-# The HFST c++ extension
 libhfst_module = Extension('_libhfst',
                            language = "c++",
-                           sources = ["libhfst.i"] + libhfst_source_files,
+                           sources = ext_source + libhfst_source_files,
                            swig_opts = ext_swig_opts,
                            include_dirs = ext_include_dirs,
-                           library_dirs = ext_library_dirs,
-                           libraries = ext_libraries,
                            define_macros = ext_define_macros,
                            extra_link_args = ext_extra_link_args,
-                           extra_compile_args = ext_extra_compile_args,
-                           extra_objects = foma_object_files
+                           extra_compile_args = ext_extra_compile_args
                            )
 
 setup(name = 'hfst',
-      version = '3.12.2.0_beta',
+      version = '3.13.0.0_beta',
       author = 'HFST team',
       author_email = 'hfst-bugs at helsinki.fi',
       url = 'http://hfst.github.io/',
@@ -230,5 +353,6 @@ setup(name = 'hfst',
       ext_modules = [libhfst_module],
       py_modules = ["libhfst"],
       packages = ["hfst", "hfst.exceptions", "hfst.sfst_rules", "hfst.xerox_rules"],
+      package_data = ext_package_data,
       data_files = []
       )
diff --git a/python/setup.py b/python/setup.py
index 36a9d89..52f4437 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -7,20 +7,36 @@ setup for HFST-swig
 import os
 from distutils.core import setup, Extension
 
+# handle hfst-specific commands
+import sys
+local_hfst=False
+if '--local-hfst' in sys.argv:
+        index = sys.argv.index('--local-hfst')
+        sys.argv.pop(index)
+        local_hfst=True
+
+from sys import platform
+
 libhfst_src_path = '../libhfst/src/'
 absolute_libhfst_src_path = os.path.abspath(libhfst_src_path)
 
 extra_link_arguments = []
-# If you wish to link to the local HFST library, replace the above with:
-# extra_link_arguments = ["-Wl,-rpath=" + absolute_libhfst_src_path + "/.libs"]
+if platform == "darwin":
+        extra_link_arguments.extend(['-mmacosx-version-min=10.7'])
+
+# If you wish to link to the local HFST library:
+if local_hfst:
+        extra_link_arguments.extend(["-Wl,-rpath=" + absolute_libhfst_src_path + "/.libs"])
 
-# When making the debian package, replace extra_link_args
-# with ["-L/usr/lib/", "-Wl,-rpath=/usr/lib/"]
+extra_compile_arguments = ['-std=c++0x']
+if platform == "darwin":
+        extra_compile_arguments.extend(["-stdlib=libc++", "-mmacosx-version-min=10.7"])
 
 # If you wish to link hfst c++ library statically, use:
 # library_dirs = []
 # libraries = []
 # extra_objects = absolute_libhfst_src_path + "/.libs/libhfst.a"
+
 libhfst_module = Extension('_libhfst',
                            language = "c++",
                            sources = ["libhfst.i"],
@@ -29,14 +45,12 @@ libhfst_module = Extension('_libhfst',
                            include_dirs = [absolute_libhfst_src_path],
                            library_dirs = [absolute_libhfst_src_path + "/.libs"],
                            libraries = ["hfst"],
-                           extra_compile_args = ["-std=c++0x"],
+                           extra_compile_args = extra_compile_arguments,
                            extra_link_args = extra_link_arguments
                            )
-# When making the windows package, replace data_files with
-# ["libhfst-NN.dll", "libgcc_s_seh-1.dll"] or
-# ["libhfst-NN.dll", "libgcc_s_dw2-1.dll"] or
+
 setup(name = 'libhfst_swig',
-      version = '3.12.2_beta',
+      version = '3.13.0_beta',
       author = 'HFST team',
       author_email = 'hfst-bugs at helsinki.fi',
       url = 'http://hfst.github.io/',
diff --git a/python/test/Makefile.am b/python/test/Makefile.am
index c867790..b352639 100644
--- a/python/test/Makefile.am
+++ b/python/test/Makefile.am
@@ -1,9 +1,11 @@
 EXTRA_DIST = README test.sh \
-	test_fail.xfst testfile.att testfile_fail.att test_pass.xfst test.lexc test.sfstpl \
+	test_fail.xfst testfile.att testfile_fail.att testfile_unicode.att test_pass.xfst test.lexc test.sfstpl \
 	cats_and_dogs.prolog cats_and_dogs_fail.prolog \
 	test_pmatch.py test_prolog.py test_exceptions.py test_dir_hfst.py \
 	test_dir_hfst_exceptions.py test_dir_hfst_sfst_rules.py test_tokenizer.py \
 	test_read_att_transducer.py test_xre.py test_hfst.py test_examples.py \
 	test_att_reader.py test_prolog_reader.py \
 	test_streams_1.py test_streams_2.py test_streams_3.py streets.txt \
-	test_xerox_rules.py
+	test_xerox_rules.py test_twolc.py \
+	calculate_functionality.py cat2dog.att cat2dog.sfstpl four_plus_cats.att four_plus_cats.sfstpl \
+	test1.twolc test2.twolc test3.twolc
diff --git a/python/test/test.sh b/python/test/test.sh
index 43dcb47..9cef269 100755
--- a/python/test/test.sh
+++ b/python/test/test.sh
@@ -1,91 +1,83 @@
 
 PYTHON="python3"
 PYTHONPATH=""
+VERBOSITY=""
 
 if [ "$1" = "--help" -o "$1" = "-h" ]; then
     echo ""
     echo "Run all tests in this folder."
     echo ""
-    echo "Usage: test.sh [--python PYTHON] [--pythonpath PATH]"
+    echo "Usage: test.sh [--python PYTHON] [--pythonpath PATH] [--verbose] [--silent]"
     echo ""
-    echo "PYTHON: the python to be used for testing, defaults to 'python3'"
-    echo "PATH:   insert PATH to sys.path before running each test"
+    echo "PYTHON:    the python to be used for testing, defaults to 'python3'"
+    echo "PATH:      full path to insert to sys.path before running each test"
+    echo "--verbose: show output of tests"
+    echo "--silent:  do not print output"
     echo ""
     exit 0
 fi
 
-if [ "$1" = "--python" ]; then
-    PYTHON=$2
-fi
-
-if [ "$1" = "--pythonpath" ]; then
-    PYTHONPATH=$2
-fi
-
-if [ "$3" = "--python" ]; then
-    PYTHON=$4
-fi
-
-if [ "$3" = "--pythonpath" ]; then
-    PYTHONPATH=$4
-fi
+python="false"
+pythonpath="false"
+for arg in $@;
+do
+    if [ "$python" = "true" ]; then
+	PYTHON=$arg
+	python="false"
+    elif [ "$pythonpath" = "true" ]; then
+	PYTHONPATH=$arg
+	pythonpath="false"
+    elif [ "$arg" = "--python" ]; then
+	python="true"
+    elif [ "$arg" = "--pythonpath" ]; then
+	pythonpath="true"
+    elif [ "$arg" = "--verbose" ]; then
+	VERBOSITY="verbose"
+    elif [ "$arg" = "--silent" ]; then
+	VERBOSITY="silent"
+    else
+	echo "warning: skipping unknown argument '"$arg"'";
+    fi
+done
 
 for file in test_dir_hfst.py test_dir_hfst_exceptions.py test_dir_hfst_sfst_rules.py \
     test_tokenizer.py test_exceptions.py test_xre.py \
     test_read_att_transducer.py test_prolog.py \
     test_att_reader.py test_prolog_reader.py \
-    test_pmatch.py test_xerox_rules.py;
+    test_pmatch.py test_xerox_rules.py \
+    test_hfst.py test_examples.py test_twolc.py;
 do
-    if ! [ "$PYTHONPATH" = "" ]; then
-        echo 'import sys' > tmp
-        echo 'sys.path.insert(0, "'$PYTHONPATH'")' >> tmp
-        cat $file >> tmp
+    if [ "$VERBOSITY" = "verbose" ]; then
+	$PYTHON $file $PYTHONPATH
     else
-        cat $file > tmp
+	$PYTHON $file $PYTHONPATH 2> /dev/null > /dev/null
     fi
-    if ( $PYTHON tmp 2> /dev/null > /dev/null ); then
-        echo $file" passed"
+    if [ "$?" = "0" ]; then
+	if ! [ "$VERBOSITY" = "silent" ]; then
+            echo $file" passed"
+	fi
     else
-        echo $file" failed"
+	if ! [ "$VERBOSITY" = "silent" ]; then
+            echo $file" failed"
+	fi
         exit 1
     fi
 done
 
-# give pythonpath as argument, from __future__ statement must come first
-for file in test_hfst.py test_examples.py;
-do
-    if ( $PYTHON $file $PYTHONPATH 2> /dev/null > /dev/null ); then
-        echo $file" passed"
-    else
-        echo $file" failed"
-        exit 1
-    fi
-done
-
-if ! [ "$PYTHONPATH" = "" ]; then
-    echo 'import sys' > tmp1
-    echo 'sys.path.insert(0, "'$PYTHONPATH'")' >> tmp1
-    cat test_streams_1.py >> tmp1
-    echo 'import sys' > tmp2
-    echo 'sys.path.insert(0, "'$PYTHONPATH'")' >> tmp2
-    cat test_streams_2.py >> tmp2
-    echo 'import sys' > tmp3
-    echo 'sys.path.insert(0, "'$PYTHONPATH'")' >> tmp3
-    cat test_streams_3.py >> tmp3
-else
-    cat test_streams_1.py > tmp1
-    cat test_streams_2.py > tmp2
-    cat test_streams_3.py > tmp3
-fi
-
 for format in sfst openfst foma;
 do
-    if ( $PYTHON tmp1 $format | $PYTHON tmp2 $format | $PYTHON tmp3 $format ); then
-        echo "test_streams[1|2|3].py with "$format" format passed"
+    if ( $PYTHON test_streams_1.py $format $PYTHONPATH | $PYTHON test_streams_2.py $format $PYTHONPATH | $PYTHON test_streams_3.py $format $PYTHONPATH ); then
+	if ! [ "$VERBOSITY" = "silent" ]; then
+            echo "test_streams[1|2|3].py with "$format" format passed"
+	fi
     elif [ "$?" = "77" ]; then
-        echo "test_streams[1|2|3].py with "$format" format skipped"
+	if ! [ "$VERBOSITY" = "silent" ]; then
+            echo "test_streams[1|2|3].py with "$format" format skipped"
+	fi
     else
-        echo "test_streams[1|2|3].py with "$format" format failed"
+	if ! [ "$VERBOSITY" = "silent" ]; then
+            echo "test_streams[1|2|3].py with "$format" format failed"
+	fi
         exit 1
     fi
 done
@@ -94,7 +86,3 @@ rm foo
 rm foo_att_prolog
 rm testfile3.att
 rm testfile_.att
-rm tmp
-rm tmp1
-rm tmp2
-rm tmp3
diff --git a/tools/src/hfst-twolc/test/test5 b/python/test/test1.twolc
similarity index 62%
copy from tools/src/hfst-twolc/test/test5
copy to python/test/test1.twolc
index e22c41b..a57d2c3 100644
--- a/tools/src/hfst-twolc/test/test5
+++ b/python/test/test1.twolc
@@ -1,4 +1,4 @@
 Alphabet a b ;
 Rules
 "rule name"
-a:b => x [a*/b] _ ;
+a:b => b _ b ;
diff --git a/tools/src/hfst-twolc/test/test5 b/python/test/test2.twolc
similarity index 62%
copy from tools/src/hfst-twolc/test/test5
copy to python/test/test2.twolc
index e22c41b..5a360e2 100644
--- a/tools/src/hfst-twolc/test/test5
+++ b/python/test/test2.twolc
@@ -1,4 +1,4 @@
 Alphabet a b ;
 Rules
 "rule name"
-a:b => x [a*/b] _ ;
+a:b => x a _ ;
diff --git a/tools/src/hfst-twolc/test/test5 b/python/test/test3.twolc
similarity index 62%
copy from tools/src/hfst-twolc/test/test5
copy to python/test/test3.twolc
index e22c41b..77311f8 100644
--- a/tools/src/hfst-twolc/test/test5
+++ b/python/test/test3.twolc
@@ -1,4 +1,4 @@
 Alphabet a b ;
 Rules
 "rule name"
-a:b => x [a*/b] _ ;
+a:b => x a* _ ;
diff --git a/python/test/test_att_reader.py b/python/test/test_att_reader.py
index 18b3b3b..660cf26 100644
--- a/python/test/test_att_reader.py
+++ b/python/test/test_att_reader.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 transducers = []
@@ -23,3 +27,14 @@ with open('testfile_fail.att', 'r') as f:
 
 assert(f.closed)
 assert(len(transducers)) == 4
+
+transducers = []
+with open('testfile_unicode.att', 'r') as f:
+    r = hfst.AttReader(f)
+    for tr in r:
+        transducers.append(tr)
+
+assert(f.closed)
+assert(len(transducers)) == 1
+TR = hfst.regex('föö:bär::0.5')
+assert(TR.compare(transducers[0]))
diff --git a/python/test/test_dir_hfst.py b/python/test/test_dir_hfst.py
index 144fcb3..0ad2bb4 100644
--- a/python/test/test_dir_hfst.py
+++ b/python/test/test_dir_hfst.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 diritems = \
diff --git a/python/test/test_dir_hfst_exceptions.py b/python/test/test_dir_hfst_exceptions.py
index 7d2e647..453cd35 100644
--- a/python/test/test_dir_hfst_exceptions.py
+++ b/python/test/test_dir_hfst_exceptions.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst.exceptions
 
 diritems = \
diff --git a/python/test/test_dir_hfst_sfst_rules.py b/python/test/test_dir_hfst_sfst_rules.py
index d8d6e41..c0707bf 100644
--- a/python/test/test_dir_hfst_sfst_rules.py
+++ b/python/test/test_dir_hfst_sfst_rules.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst.sfst_rules
 
 diritems = \
diff --git a/python/test/test_examples.py b/python/test/test_examples.py
index 2aaad0a..5c12425 100644
--- a/python/test/test_examples.py
+++ b/python/test/test_examples.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # The examples given in doxygen documentation
 from __future__ import print_function
 import sys
diff --git a/python/test/test_exceptions.py b/python/test/test_exceptions.py
index 09bd71f..183b8f4 100644
--- a/python/test/test_exceptions.py
+++ b/python/test/test_exceptions.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst.exceptions
 
 # HfstException and its subclasses
diff --git a/python/test/test_hfst.py b/python/test/test_hfst.py
index 4804aa0..3f6e566 100644
--- a/python/test/test_hfst.py
+++ b/python/test/test_hfst.py
@@ -21,10 +21,11 @@ if hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.
     types.append(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)
 if hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE):
     types.append(hfst.ImplementationType.FOMA_TYPE)
+    print('HERE!!!')
 
 for type in types:
 
-    # print('\n--- Testing implementation type %s ---\n' % hfst.fst_type_to_string(type))
+    print('\n--- Testing implementation type %s ---\n' % hfst.fst_type_to_string(type))
 
     hfst.set_default_fst_type(type)
 
@@ -269,12 +270,15 @@ for type in types:
     # Special inputs
     test_fst('*** FOO ***', '{*** FOO ***}')
 
-    try:
-        foo = hfst.fst('')
-        raise RuntimeError(get_linenumber())
-    except RuntimeError as e:
-        if not e.__str__() == 'Empty word.':
-            raise RuntimeError(get_linenumber())
+    foo = hfst.fst('')
+    eps = hfst.epsilon_fst()
+    assert(foo.compare(eps))
+    #try:
+    #    foo = hfst.fst('')
+    #    raise RuntimeError(get_linenumber())
+    #except RuntimeError as e:
+    #    if not e.__str__() == 'Empty word.':
+    #        raise RuntimeError(get_linenumber())
 
     # Create transducer:
     # unweighted
@@ -292,18 +296,24 @@ for type in types:
     # Special inputs
     test_fst({'*** FOO ***':'+++ BAR +++'}, '{*** FOO ***}:{+++ BAR +++}')
 
-    try:
-        foo = hfst.fst({'':'foo'})
-        raise RuntimeError(get_linenumber())
-    except RuntimeError as e:
-        if not e.__str__() == 'Empty word.':
-            raise RuntimeError(get_linenumber())
-    try:
-        foo = hfst.fst({'foo':''})
-        raise RuntimeError(get_linenumber())
-    except RuntimeError as e:
-        if not e.__str__() == 'Empty word.':
-            raise RuntimeError(get_linenumber())
+    foo = hfst.fst({'':'foo'})
+    tr = hfst.regex('0:{foo}')
+    assert(foo.compare(tr))
+    foo = hfst.fst({'foo':''})
+    tr = hfst.regex('{foo}:0')
+    assert(foo.compare(tr))
+    #try:
+    #    foo = hfst.fst({'':'foo'})
+    #    raise RuntimeError(get_linenumber())
+    #except RuntimeError as e:
+    #    if not e.__str__() == 'Empty word.':
+    #        raise RuntimeError(get_linenumber())
+    #try:
+    #    foo = hfst.fst({'foo':''})
+    #    raise RuntimeError(get_linenumber())
+    #except RuntimeError as e:
+    #    if not e.__str__() == 'Empty word.':
+    #        raise RuntimeError(get_linenumber())
 
     # Tokenized input
     def test_tokenized(tok, pathin, pathout, exp, weight=0):
diff --git a/python/test/test_pmatch.py b/python/test/test_pmatch.py
index 869f108..19d3750 100644
--- a/python/test/test_pmatch.py
+++ b/python/test/test_pmatch.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 import os.path
diff --git a/python/test/test_prolog.py b/python/test/test_prolog.py
index a3d6584..0830cfb 100644
--- a/python/test/test_prolog.py
+++ b/python/test/test_prolog.py
@@ -1,5 +1,8 @@
-import hfst
+# -*- coding: utf-8 -*-
 import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
+import hfst
 
 for type in [hfst.ImplementationType.SFST_TYPE, hfst.ImplementationType.TROPICAL_OPENFST_TYPE, hfst.ImplementationType.FOMA_TYPE]:
     if hfst.HfstTransducer.is_implementation_type_available(type):
diff --git a/python/test/test_prolog_reader.py b/python/test/test_prolog_reader.py
index 617e2d2..54094f2 100644
--- a/python/test/test_prolog_reader.py
+++ b/python/test/test_prolog_reader.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 transducers = []
diff --git a/python/test/test_read_att_transducer.py b/python/test/test_read_att_transducer.py
index a5c380e..d5f5550 100644
--- a/python/test/test_read_att_transducer.py
+++ b/python/test/test_read_att_transducer.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 for type in [hfst.ImplementationType.SFST_TYPE, hfst.ImplementationType.TROPICAL_OPENFST_TYPE, hfst.ImplementationType.FOMA_TYPE]:
diff --git a/python/test/test_streams_1.py b/python/test/test_streams_1.py
index 085961d..12ceac5 100644
--- a/python/test/test_streams_1.py
+++ b/python/test/test_streams_1.py
@@ -1,7 +1,11 @@
 # -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 2:
+    sys.path.insert(0, sys.argv[2])
 import hfst
+if len(sys.argv) < 1:
+    raise RuntimeError('Transducer format must be given as first argument')
 
-import sys
 if sys.argv[1] == 'sfst':
     if not hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE):
         sys.exit(77)
diff --git a/python/test/test_streams_2.py b/python/test/test_streams_2.py
index 3d03998..35eddcb 100644
--- a/python/test/test_streams_2.py
+++ b/python/test/test_streams_2.py
@@ -1,6 +1,10 @@
 # -*- coding: utf-8 -*-
-import hfst
 import sys
+if len(sys.argv) > 2:
+    sys.path.insert(0, sys.argv[2])
+import hfst
+if len(sys.argv) < 1:
+    raise RuntimeError('Transducer format must be given as first argument')
 
 if sys.argv[1] == 'sfst':
     if not hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE):
diff --git a/python/test/test_streams_3.py b/python/test/test_streams_3.py
index e36949d..889a8a3 100644
--- a/python/test/test_streams_3.py
+++ b/python/test/test_streams_3.py
@@ -1,6 +1,10 @@
 # -*- coding: utf-8 -*-
-import hfst
 import sys
+if len(sys.argv) > 2:
+    sys.path.insert(0, sys.argv[2])
+import hfst
+if len(sys.argv) < 1:
+    raise RuntimeError('Transducer format must be given as first argument')
 
 if sys.argv[1] == 'sfst':
     if not hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE):
diff --git a/python/test/test_tokenizer.py b/python/test/test_tokenizer.py
index 3cfc299..1d240af 100644
--- a/python/test/test_tokenizer.py
+++ b/python/test/test_tokenizer.py
@@ -1,6 +1,8 @@
 # -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
-from sys import version
 
 for type in [hfst.ImplementationType.SFST_TYPE, hfst.ImplementationType.TROPICAL_OPENFST_TYPE, hfst.ImplementationType.FOMA_TYPE]:
     if hfst.HfstTransducer.is_implementation_type_available(type):
@@ -60,7 +62,7 @@ for type in [hfst.ImplementationType.SFST_TYPE, hfst.ImplementationType.TROPICAL
         assert tok.tokenize_space_separated('foobar') == \
             (('foobar', 'foobar'),)
 
-        if int(version[0]) > 2:
+        if int(sys.version[0]) > 2:
             try:
                 hfst.HfstTokenizer.check_utf8_correctness('föö')
             except hfst.exceptions.IncorrectUtf8CodingException as e:
diff --git a/python/test/test_twolc.py b/python/test/test_twolc.py
new file mode 100644
index 0000000..e95cf72
--- /dev/null
+++ b/python/test/test_twolc.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
+import hfst
+
+for n in [1, 2, 3]:
+    assert(hfst.compile_twolc_file('test'+str(n)+'.twolc', 'test'+str(n)+'.hfst') == 0)
+
+if hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE):
+    for n in [1, 2, 3]:
+        assert(hfst.compile_twolc_file('test'+str(n)+'.twolc', 'test'+str(n)+'.hfst', verbose=True, type=hfst.ImplementationType.FOMA_TYPE) == 0)
diff --git a/python/test/test_xerox_rules.py b/python/test/test_xerox_rules.py
index 011f19e..a152ded 100644
--- a/python/test/test_xerox_rules.py
+++ b/python/test/test_xerox_rules.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 types = []
diff --git a/python/test/test_xre.py b/python/test/test_xre.py
index 9892fac..c2e65ca 100644
--- a/python/test/test_xre.py
+++ b/python/test/test_xre.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+import sys
+if len(sys.argv) > 1:
+    sys.path.insert(0, sys.argv[1])
 import hfst
 
 for type in [hfst.ImplementationType.SFST_TYPE, hfst.ImplementationType.TROPICAL_OPENFST_TYPE, hfst.ImplementationType.FOMA_TYPE]:
diff --git a/python/test/testfile_unicode.att b/python/test/testfile_unicode.att
new file mode 100644
index 0000000..7e0b79f
--- /dev/null
+++ b/python/test/testfile_unicode.att
@@ -0,0 +1,2 @@
+0 1 föö bär 0.5
+1
diff --git a/scripts/copy-for-windows.sh b/scripts/copy-for-windows.sh
index 6dd04cb..0528d74 100755
--- a/scripts/copy-for-windows.sh
+++ b/scripts/copy-for-windows.sh
@@ -225,7 +225,7 @@ do
         $1/libhfst/src/parsers/$file.hh
 done
 
-for file in xfst-lexer htwolcpre1-lexer htwolcpre2-lexer htwolcpre3-lexer;
+for file in xfst-lexer htwolcpre1-lexer htwolcpre2-lexer htwolcpre3-lexer sfst-scanner;
 do
     sed -i 's/#include <unistd.h>/#include <io.h>/' $1/libhfst/src/parsers/$file.cpp
     sed -i 's/hxfstwrap( )/hxfstwrap(void)/' $1/libhfst/src/parsers/$file.cpp
@@ -352,7 +352,7 @@ do
 done
 
 # twolc
-cp tools/src/hfst-twolc/src/htwolc-main.cc $1/tools/src/hfst-twolc/src/hfst-twolc.cpp 
+cp tools/src/hfst-twolc/src/hfst-twolc.cc $1/tools/src/hfst-twolc/src/hfst-twolc.cpp 
 
 # compare, strings2fst and txt2fst are needed for testing hfst-xfst
 for file in \
diff --git a/scripts/finnish-tagtools/finnish-nertag b/scripts/finnish-tagtools/finnish-nertag
new file mode 100755
index 0000000..9823062
--- /dev/null
+++ b/scripts/finnish-tagtools/finnish-nertag
@@ -0,0 +1,60 @@
+#!/bin/bash
+BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TAGGER=$BASE/omotag/run_tagger
+PMATCH=hfst-pmatch
+MOVETAGS=$BASE/move_tags
+DISAMB_LEMMA=$BASE/omotag/lemmafilter
+
+if command -v hfst-tokenize 2 > /dev/null; then
+    TOKENIZE="hfst-tokenize $BASE/tokenize.pmatch"
+else
+    TOKENIZE="python3 $BASE/tokenize.py"
+fi
+
+function print_help()
+{
+    echo "Adds named entity tags to running Finnish text on standard input."
+    echo
+    echo "The output is returned one token per line. Where named entities are"
+    echo "identified, the token in question is followed by a tab character and"
+    echo "the entity identifier. Entities that span multiple tokens are given"
+    echo "opening and closing XML-style tags, and single-token entities only a"
+    echo "closing tag."
+    echo
+    echo "This package is based on the statistical (CRF-based) tagger FinnPos,"
+    echo "the Finnish morphology package OmorFi, the FinnTreeBank corpus of"
+    echo "labeled text and the FinnPos rule-based named entity tagger."
+    echo
+    echo "Process entire files with redirection, eg."
+    echo "  $ finnish-nertag < mytext.txt > mytext_tagged.txt"
+    echo "or type into the terminal and terminate with EOF (usually ctrl-D on"
+    echo "your keyboard), or directly input a line of text with <<<. Example:"
+    echo
+        
+    echo "$ finnish-nertag <<< \"Pernoossa asuva Heikki Anttonen on ostanut Outokummun osakkeita.\""
+    echo "Pernoossa	<EnamexLocXxx/>"
+    echo "asuva	"
+    echo "Heikki	<EnamexPrsHum>"
+    echo "Anttonen	</EnamexPrsHum>"
+    echo "on	"
+    echo "ostanut	"
+    echo "Outokummun	<EnamexOrgCrp/>"
+    echo "osakkeita	"
+    echo ".	"
+    exit 0
+}
+
+case $1 in
+    "")
+	;;
+    *)
+	print_help ;;
+esac
+
+$TOKENIZE |
+$BASE/hfst-optimized-lookup $BASE/combined_morphology.hfst 2>/dev/null |
+python3 $BASE/omorfi2finnpos.py ftb                               |
+python3 $BASE/finnpos-ratna-feats.py $BASE/freq_words              |
+$BASE/finnpos-label $BASE/ftb.omorfi.model 2>/dev/null             |
+python3 $BASE/finnpos-restore-lemma.py --finer                     |
+$BASE/prefilt_tags | $PMATCH $BASE/proper_tagger_ph1.pmatch | $MOVETAGS | $PMATCH $BASE/proper_tagger_ph2.pmatch | $MOVETAGS | $BASE/remove_exc | cut -f1,5
diff --git a/scripts/finnish-tagtools/finnish-postag b/scripts/finnish-tagtools/finnish-postag
new file mode 100755
index 0000000..7322cef
--- /dev/null
+++ b/scripts/finnish-tagtools/finnish-postag
@@ -0,0 +1,45 @@
+#! /bin/bash
+
+function print_help()
+{
+    echo "Lemmatizes and morphologically labels running Finnish text on standard input."
+    echo
+    echo "This package is based on the statistical (CRF-based) tagger FinnPos,"
+    echo "the Finnish morphology package OmorFi and the FinnTreeBank corpus of"
+    echo "labeled text."
+    echo
+    echo "Process entire files with redirection, eg."
+    echo "  $ finnish-postag < mytext.txt > mytext_tagged.txt"
+    echo "or type into the terminal and terminate with EOF (usually ctrl-D on"
+    echo "your keyboard), or directly input a line of text with <<<. Example:"
+    echo
+    echo "$ finnish-postag <<< \"Voitteko ojentaa voita?\""
+    echo ""
+    echo "Voitteko	voida	[POS=VERB]|[VOICE=ACT]|[MOOD=INDV]|[TENSE=PRESENT]|[PERS=PL2]|[CLIT=KO]"
+    echo "ojentaa	ojentaa	[POS=VERB]|[VOICE=ACT]|[MOOD=INDV]|[TENSE=PRESENT]|[PERS=SG3]"
+    echo "voita	voi	[POS=NOUN]|[NUM=SG]|[CASE=PAR]"
+    echo "?	?	[POS=PUNCTUATION]"
+    exit 0
+}
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+if command -v hfst-tokenize 2 > /dev/null; then
+    TOKENIZE="hfst-tokenize $DIR/tokenize.pmatch"
+else
+    TOKENIZE="python3 $DIR/tokenize.py"
+fi
+
+case $1 in
+    "")
+	;;
+    *)
+	print_help ;;
+esac
+
+$TOKENIZE |
+$DIR/hfst-optimized-lookup $DIR/morphology.omor.hfst 2>/dev/null |
+python3 $DIR/omorfi2finnpos.py ftb                               |
+python3 $DIR/finnpos-ratna-feats.py $DIR/freq_words              |
+$DIR/finnpos-label $DIR/ftb.omorfi.model 2>/dev/null             |
+python3 $DIR/finnpos-restore-lemma.py                           |
+cut -f1,3,4
diff --git a/scripts/finnish-tagtools/finnpos-ratna-feats.py b/scripts/finnish-tagtools/finnpos-ratna-feats.py
new file mode 100644
index 0000000..f3dd237
--- /dev/null
+++ b/scripts/finnish-tagtools/finnpos-ratna-feats.py
@@ -0,0 +1,181 @@
+#! /usr/bin/env python3
+
+"""@package ratna_feats
+
+ file    finnpos-ratna-feats.py                                                     
+ Author  Miikka Silfverberg                                                 
+ brief   Extract Ratnaparkhi 1996 features from an input-file.              
+
+         (Adwait Ratnaparkhi: A Maximum Entropy Model for Part-of-Speech    
+          Tagging, EMNLP 1996)                                              
+          
+         Additionally use word pairs as features (previous word and
+         current word as well as current word and next word). Also use
+         the lower-cased word form as feature.
+"""
+
+"""                                                                            
+  (C) Copyright 2014, University of Helsinki                                 
+  Licensed under the Apache License, Version 2.0 (the "License");            
+  you may not use this file except in compliance with the License.           
+  You may obtain a copy of the License at                                    
+  http://www.apache.org/licenses/LICENSE-2.0                                 
+  Unless required by applicable law or agreed to in writing, software        
+  distributed under the License is distributed on an "AS IS" BASIS,          
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
+  See the License for the specific language governing permissions and        
+  limitations under the License.
+"""
+
+from sys import stdin, stdout, stderr, argv
+from re  import match
+from os  import linesep
+
+EXIT_FAIL    = 1
+EXIT_SUCCESS = 0
+
+# Boundary word.
+BOUNDARY = "_#_"
+
+# Maximum length of extracted suffix and prefix features.
+MAX_SUF_LEN = 10
+MAX_PRE_LEN = 10
+
+def main(pname, iname, ifile, oname, ofile, olog, freq_words):
+    """ Read input from ifile and write extracted features to ofile. 
+        This function doesn't check its argument streams. """
+
+    i = 0
+
+    while ifile:
+        sentence = []
+
+        # Split file into sentences and check syntax.
+        for line in ifile:            
+            line = line.strip()
+
+            if len(line) == 0:
+                break
+
+            else:
+                fields = line.split('\t')
+
+                if len(fields) != 1 and len(fields) != 3 and len(fields) != 5:
+                    print(fields)
+                    olog.write(("Line %u in file %s: Incorrect field count %u. " +
+                                "Should be 1, 3 or 5." + linesep) 
+                               % 
+                               (i + 1, iname, len(fields)))
+
+                    return EXIT_FAIL
+
+            sentence.append(fields)
+
+            i += 1
+        else:
+            i += 1
+            if sentence == []:
+                break
+
+        if sentence == []:
+            continue
+
+        # Extract features for each sentence and write output to ofile.
+        for i, line in enumerate(sentence):
+            wf    = '_'
+            feats = '_'
+            lemma = '_'
+            label = '_'
+            ann   = '_'
+            
+            if len(line) == 1:
+                wf = line[0]
+                lemma, label, ann = '_', '_', '_'
+            elif len(line) == 3:
+                wf, lemma, label = line
+                ann = "_"
+            else:
+                wf, feats, lemma, label, ann = line
+
+            features = []                
+
+            if feats != '_':
+                features = feats.split(' ')
+
+            if not ann in ['_', '']:
+                lemma_list = ann
+                if ' ' in ann:
+                    lemma_list = ann[:ann.find(' ')]
+                
+                label_feats = [ "FEAT:" + label for label in 
+                                map(lambda x: x[0], eval(lemma_list)) ]
+
+                if len(label_feats) != 0:
+                    features += label_feats
+                else:
+                    features.append("NO_LABELS")
+
+            features.append('PPWORD=' + get_wf(i - 2, sentence))
+            features.append('PWORD='  + get_wf(i - 1, sentence))
+            features.append('WORD='   + wf)
+            features.append('WORD_LEN='   + str(len(wf)))
+            features.append('NWORD='  + get_wf(i + 1, sentence))
+            features.append('NNWORD=' + get_wf(i + 2, sentence))
+            
+            features.append('PWORDPAIR='  + get_wf(i - 1, sentence) + "_" + wf)
+            features.append('NWORDPAIR='  + wf + "_" + get_wf(i + 1, sentence))
+            
+            features.append("LC_WORD=" + wf.lower())
+            
+            if not wf in freq_words:
+                features += get_suffixes(wf)
+                features += get_prefixes(wf)
+            
+                features.append(has_uc(wf))
+                features.append(has_digit(wf))
+                features.append(has_dash(wf))
+            
+            feat_str = " ".join(filter(None, features))
+        
+        
+            ofile.write(("%s\t%s\t%s\t%s\t%s" + linesep) 
+                        % 
+                        (wf, feat_str, lemma, label, ann))
+        
+        ofile.write(linesep)
+        
+        # Ensure that the line is written immediately so that features
+        # get passed to finnpos-label in real time when labeling text
+        # from a stream.
+        ofile.flush()
+
+    return EXIT_SUCCESS
+
+def get_wf(i, sentence):
+    return BOUNDARY if i < 0 or i + 1 > len(sentence) else sentence[i][0]
+
+def get_suffixes(wf):
+    return [ "%u-SUFFIX=%s" % (i, wf[-i:]) 
+             for i in range(1, min(MAX_SUF_LEN + 1, len(wf) + 1)) ]
+
+def get_prefixes(wf):
+    return [ "%u-PREFIX=%s" % (i, wf[:i]) 
+             for i in range(1, min(MAX_PRE_LEN + 1, len(wf) + 1)) ]
+
+def has_uc(wf):
+    return "HAS_UC" if match(".*([A-Z]|Å|Ä|Ö).*", wf) else None
+
+def has_digit(wf):
+    return "HAS_DIGIT" if match(".*[0-9].*", wf) else None
+
+def has_dash(wf):
+    return "HAS_DASH" if match(".*-.*", wf) else None
+
+if __name__ == "__main__":
+    if len(argv) != 2:
+        stderr.write("cat data | %s freq_word_list\n" % argv[0])
+        exit(1)
+
+    freq_words = set(open(argv[1]).read().split('\n'))
+
+    exit(main(argv[0], "STDIN", stdin, "STDOUT", stdout, stderr, freq_words))
diff --git a/scripts/finnish-tagtools/finnpos-restore-lemma.py b/scripts/finnish-tagtools/finnpos-restore-lemma.py
new file mode 100644
index 0000000..d1cb9d7
--- /dev/null
+++ b/scripts/finnish-tagtools/finnpos-restore-lemma.py
@@ -0,0 +1,69 @@
+#! /usr/bin/env python3
+
+from sys import stdin, stdout, argv
+
+for_finer = False
+if len(argv) > 1 and argv[1] == "--finer":
+    for_finer = True
+
+def part_count(lemma):
+    return lemma.count('#')
+
+def compile_dict(label_lemma_pairs):
+    res = {}
+
+    for label, lemma in label_lemma_pairs:
+        if label in res:
+            old_lemma = res[label]
+
+            if part_count(old_lemma) > part_count(lemma):
+                res[label] = lemma
+        else:
+            res[label] = lemma
+
+    return res
+
+def get_proptags(label2lemma):
+    proptags = set()
+    for label in label2lemma.keys():
+        for part in label.split("|"):
+            if part.startswith("[PROP="):
+                proptags.add(part)
+    return ''.join(list(proptags))
+
+for line in stdin:
+    line = line.strip()
+
+    if line == '':
+        print('')
+        stdout.flush()
+    else:
+        wf, feats, lemma, label, ann = line.split('\t')
+
+        lemmas = ann
+        if ann.find(' ') != -1:
+            lemmas = ann[:ann.find(' ')]
+            ann = ann[ann.find(' ') + 1:]
+        else:
+            ann = '_'
+        
+        lemma_dict = {}
+        if lemmas != '_':
+            lemma_dict = compile_dict(eval(lemmas))
+
+        if for_finer and "PROPER" in label:
+            PROPtags = get_proptags(lemma_dict)
+            if PROPtags != '':
+                ann = PROPtags
+        
+        if label in lemma_dict:
+            lemma = lemma_dict[label]
+            lemma = lemma.lower()
+            lemma = lemma.replace('#','')
+
+        if for_finer:
+            print('%s\t%s\t%s\t%s' % (wf, lemma,
+                                      label.replace('|',''),
+                                      ann.replace('|', '')))
+        else:
+            print('%s\t%s\t%s\t%s\t%s' % (wf, feats, lemma, label, ann))
diff --git a/scripts/finnish-tagtools/move_tags b/scripts/finnish-tagtools/move_tags
new file mode 100755
index 0000000..29df3a7
--- /dev/null
+++ b/scripts/finnish-tagtools/move_tags
@@ -0,0 +1,2 @@
+#!/bin/sh
+sed -r -e 's/^(<[^>]+>)+(.*)/\2\1/' -e 's/<\/([^>]+)>(.*)<\1>/<\1\/>\2/g' $@
diff --git a/scripts/finnish-tagtools/omorfi2finnpos.py b/scripts/finnish-tagtools/omorfi2finnpos.py
new file mode 100644
index 0000000..2b940f7
--- /dev/null
+++ b/scripts/finnish-tagtools/omorfi2finnpos.py
@@ -0,0 +1,128 @@
+from sys import stdin, argv, stderr, stdout
+from re import findall
+
+def get_lemma(string, convert_type):
+    if convert_type == 'ftb':
+        word_id_strs = findall('\[WORD_ID=[^\]]*\]', string)
+        lemma_parts = [ word_id_str[9:][:-1] for word_id_str in word_id_strs ]
+        return '#'.join(lemma_parts)
+    else:
+        return string[:string.find('\t')]
+
+def get_label(string, convert_type):
+    if convert_type == 'ftb':
+        # Remove everything up to the start of the last lemma.
+        string = string[string.rfind('[WORD_ID=') + len('[WORD_ID='):]
+    
+        # Remove the last lemma.
+        label = string[string.find(']') + 1:]
+
+        # Add sub label separators.
+        label = label.replace('][',']|[')
+
+        sub_labels = label.split('|')
+
+        sub_labels = filter(lambda x: x.find("STYLE=") == -1, sub_labels)
+        sub_labels = filter(lambda x: x.find("DRV=") == -1, sub_labels)
+        
+        label = '|'.join(sub_labels)
+
+        return label
+
+    else:
+        return string[string.find('\t'):]
+
+def get_lemmas(analyses, convert_type):
+    return [(get_label(a, convert_type), get_lemma(a, convert_type)) 
+            for a in analyses]
+
+def get_labels(analyses, convert_type):
+    return [get_label(a, convert_type) for a in analyses]
+
+def filter_ftb_analyses(analyses):
+    min_wbs = min(map(lambda x: x.count('[WORD_ID='), analyses))
+    return list(filter(lambda x: x.count('[WORD_ID=') == min_wbs, analyses))
+
+def convert(pname, ifile, convert_type):
+    wf       = ''
+    analyses = []
+
+    for line in ifile:
+        line = line.strip()
+
+        if line == '' and wf != '':
+
+            if convert_type == 'ftb' and len(analyses) > 0:
+                analyses = filter_ftb_analyses(analyses)
+
+            lemmas = get_lemmas(analyses, convert_type)
+            lemmas = list(set(lemmas))
+
+            lemma_str = str(lemmas).replace(' ','')
+
+            labels = get_labels(analyses, convert_type)
+
+            feats = '_'
+
+            if labels != []:
+                label_feats = map(lambda x: "OMORFI_FEAT:" + x, labels)
+                feats = ' '.join(label_feats)
+
+            label_str = '_'
+
+            if labels != []:
+                label_str = ' '.join(labels)
+                
+            print('%s\t%s\t%s\t%s\t%s' % (wf, feats, '_', label_str, lemma_str))
+
+            wf, analyses = '', []
+            
+        elif line == '':
+            stdout.flush()
+            continue
+
+        elif (convert_type == 'ftb' and 
+              line == 'OMORFI_VERSION_≥_14_©_GNU_GPL_V3'):
+            print('')
+            entry = ''
+
+        elif convert_type == 'tdt' and line.find('<END>') != -1:
+            print('')
+            entry = ''
+
+        else:
+            if convert_type == 'ftb':
+                parts = line.split('\t')
+                if len(parts) < 2:
+                    wf, analysis = ("", parts[0])
+                else:
+                    wf, analysis = (parts[0], parts[1])
+
+                if analysis == '+?':
+                    analyses = []
+                else:
+                    analyses.append(analysis)
+            else:
+                wf, lemma, label = line.split('\t')
+
+                if label == '+?':
+                    analyses = []
+                else:
+                    analyses.append(lemma + '\t' + label)
+
+if __name__=='__main__':
+
+    convert_type = 'ftb'
+
+    if len(argv) == 2:
+        convert_type = argv[1]
+    elif len(argv) != 1:
+        stderr.write('USE: cat indata | %s (ftb|tdt) > outdata\n' % argv[0])
+        exit(1)
+        
+    if not convert_type in ['ftb','tdt']:
+        stderr.write('Unknown conversion type %s. Should be ftb or tdt.' % 
+                     convert_type)
+        exit(1)
+
+    convert(argv[0], stdin, convert_type)
diff --git a/scripts/finnish-tagtools/prefilt_tags b/scripts/finnish-tagtools/prefilt_tags
new file mode 100755
index 0000000..78bfe6f
--- /dev/null
+++ b/scripts/finnish-tagtools/prefilt_tags
@@ -0,0 +1,22 @@
+#!/bin/sh
+# 1) Do some unification to the Omorfi tagging
+#  a) Add missing NUM & CASE tags
+# 2) Fix defective guessed lemmas
+# 3) Correct some >90% sure tagging errors
+#  a) 'Juhani' != Juha+PX
+#  b) 'Mari(tt)a' != Mari+PAR/ABE
+#  c) 'Kansa' != 'Ka'
+#  d) 'Line' != 'Li'
+#  e) 'noin' != 'noki'
+# 4) Add a TAB char to ends of non-empty lines
+sed -r -e 's/^(.*\t.*\t\[POS=NOUN\](\[SUBCAT=[^]]+\])*)\t/\1[NUM=SG][CASE=NOM]\t/' \
+       -e 's/^([^\t]*)\t\[POS=ADJECTIVE/\1\t\1/' \
+       -e 's/^([^\t]*[^t]\t\S+[A-ZÄÖ])t\t/\1\t/' \
+       -e 's/^([^\t]*\t\S+[0-9.])t\t/\1\t/' \
+       -e 's/^Juhani\tJuha\t(.*)\[CASE=...\]\[POSS=SG1\]/Juhani\tJuhani\t\1[CASE=NOM]/' \
+       -e 's/^Maria\t[^\t]+\t(.*)\[CASE=PAR\]/Maria\tMaria\t\1[CASE=NOM]/' \
+       -e 's/^Maritta\t[^\t]+\t(.*)\[CASE=ABE\]/Maritta\tMaritta\t\1[CASE=NOM]/' \
+       -e 's/^Kansa\tKa\t(.*)\[CASE=...\]\[POSS=3\]/Kansa\tKansa\t\1[CASE=NOM]/' \
+       -e 's/^Line\tLi\t(.*)\[CASE=COM\]/Line\tLine\t\1[CASE=NOM]/' \
+       -e 's/^([Nn])oin\tnoki\t.*\t/\1oin\tnoin\t[POS=PARTICLE][SUBCAT=ADVERB]\t/' \
+       -e 's/.$/&\t/'
diff --git a/scripts/finnish-tagtools/remove_exc b/scripts/finnish-tagtools/remove_exc
new file mode 100755
index 0000000..b5e21db
--- /dev/null
+++ b/scripts/finnish-tagtools/remove_exc
@@ -0,0 +1,2 @@
+#!/bin/sh
+sed -r 's/<\/?Exc[^>]+>//' $@
diff --git a/scripts/finnish-tagtools/tokenize.py b/scripts/finnish-tagtools/tokenize.py
new file mode 100644
index 0000000..fd25cba
--- /dev/null
+++ b/scripts/finnish-tagtools/tokenize.py
@@ -0,0 +1,31 @@
+# A very simple fallback tokenizer
+import string
+
+def print_tokenize(line):
+    if line == "":
+        return
+    parts = line.split()
+    for part in parts:
+        thispart = part
+        while thispart != "" and thispart[0] in string.punctuation:
+            print(thispart[0])
+            thispart = thispart[1:]
+        endpunct_queue = []
+        while thispart != "" and thispart[-1] in string.punctuation:
+            if thispart.endswith("..."):
+                endpunct_queue.append("...")
+                thispart = thispart[:-3]
+            else:
+                endpunct_queue.append(thispart[-1])
+                thispart = thispart[:-1]
+        if thispart != "":
+            print(thispart)
+        for endpunct in endpunct_queue[::-1]:
+            print(endpunct)
+    print("")
+
+while True:
+    try:
+        print_tokenize(input())
+    except EOFError:
+        break
diff --git a/test/tools/fsmbook-tests/CompileOptions.py b/test/tools/fsmbook-tests/CompileOptions.py
new file mode 100644
index 0000000..52c94c6
--- /dev/null
+++ b/test/tools/fsmbook-tests/CompileOptions.py
@@ -0,0 +1,25 @@
+import sys
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+    raise RuntimeError('Usage: ' + sys.argv[0] + ' [sfst|openfst|foma] [[PYTHONPATH]]')
+if len(sys.argv) == 3:
+    import sys
+    sys.path.insert(0, sys.argv[2])
+import hfst
+    
+if (sys.argv[1] == 'sfst'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.SFST_TYPE)
+    else:
+        raise RuntimeError('Format sfst is not available.')
+elif (sys.argv[1] == 'openfst' or sys.argv[1] == "openfst-tropical"):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)
+    else:
+        raise RuntimeError('Format openfst is not available.')
+elif (sys.argv[1] == 'foma'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.FOMA_TYPE)
+    else:
+        raise RuntimeError('Format foma is not available.')
+else:
+    raise RuntimeError('Transducer format "' + sys.argv[1] + '" not recognized.')
diff --git a/test/tools/fsmbook-tests/Makefile.am b/test/tools/fsmbook-tests/Makefile.am
index b5dc349..18bbcd5 100755
--- a/test/tools/fsmbook-tests/Makefile.am
+++ b/test/tools/fsmbook-tests/Makefile.am
@@ -3,6 +3,7 @@ TESTS=test.sh
 endif
 
 EXTRA_DIST=test.sh \
+compile_xfst.py \
 expected-results/BetterColaMachine.prolog \
 expected-results/EnglishNumerals.prolog \
 expected-results/EsperantoNouns.prolog \
@@ -20,6 +21,9 @@ expected-results/EsperantoNounsAndAdjectives.prolog \
 expected-results/MonishAnalysis.prolog \
 expected-results/EinsteinsPuzzle.prolog \
 expected-results/EsperantoNounsAndAdjectivesWithTags.prolog \
+expected-results/FinnishNumerals.prolog \
+expected-results/FinnishProsody.prolog \
+expected-results/Palindromes.prolog \
 expected-results/MonishGuesserAnalyzer.prolog \
 hfst-scripts/BetterColaMachine.hfst.script \
 hfst-scripts/BrazilianPortuguese1.hfst.script \
diff --git a/test/tools/fsmbook-tests/compare.py b/test/tools/fsmbook-tests/compare.py
new file mode 100644
index 0000000..1c148b1
--- /dev/null
+++ b/test/tools/fsmbook-tests/compare.py
@@ -0,0 +1,35 @@
+import sys
+if len(sys.argv) < 3 or len(sys.argv) > 6:
+    raise RuntimeError('Usage: compare.py [input1] [input2] [[PYTHONPATH]] [[--eliminate-flags]] [[-q]]')
+
+eliminate_flags=False
+for arg in sys.argv[3:]:
+    if arg == '-q':
+        pass
+    elif arg == '--eliminate-flags':
+        eliminate_flags=True
+    else:
+        sys.path.insert(0, arg)
+
+import hfst
+
+istr1 = hfst.HfstInputStream(sys.argv[1])
+istr2 = hfst.HfstInputStream(sys.argv[2])
+
+retval=0
+while(True):
+    try:
+        tr1 = istr1.read()
+        tr2 = istr2.read()
+        if (eliminate_flags):
+            tr1.eliminate_flags()
+            tr2.eliminate_flags()
+        if not (tr1.compare(tr2)):
+            retval=1
+            break
+    except hfst.exceptions.EndOfStreamException as e:
+        break
+
+istr1.close()
+istr2.close()
+sys.exit(retval)
diff --git a/test/tools/fsmbook-tests/compile_xfst.py b/test/tools/fsmbook-tests/compile_xfst.py
new file mode 100644
index 0000000..6db2030
--- /dev/null
+++ b/test/tools/fsmbook-tests/compile_xfst.py
@@ -0,0 +1,27 @@
+import sys
+if len(sys.argv) < 3 or len(sys.argv) > 4:
+    raise RuntimeError('Usage: compile_xfst.py [sfst|openfst|foma] FILENAME [[PYTHONPATH]]')
+if len(sys.argv) == 4:
+    sys.path.insert(0, sys.argv[3])
+import hfst
+
+if (sys.argv[1] == 'sfst'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.SFST_TYPE)
+    else:
+        raise RuntimeError('Format sfst is not available.')
+elif (sys.argv[1] == 'openfst' or sys.argv[1] == "openfst-tropical"):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)
+    else:
+        raise RuntimeError('Format openfst is not available.')
+elif (sys.argv[1] == 'foma'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.FOMA_TYPE)
+    else:
+        raise RuntimeError('Format foma is not available.')
+else:
+    raise RuntimeError('Transducer format "' + sys.argv[1] + '" not recognized.')
+    
+if hfst.compile_xfst_file(sys.argv[2]) != 0 :
+    raise RuntimeError('Compiling file "' + sys.argv[2] + '" failed.')
diff --git a/test/tools/fsmbook-tests/expected-results/FinnishNumerals.prolog b/test/tools/fsmbook-tests/expected-results/FinnishNumerals.prolog
new file mode 100644
index 0000000..51def58
--- /dev/null
+++ b/test/tools/fsmbook-tests/expected-results/FinnishNumerals.prolog
@@ -0,0 +1,326 @@
+network(NO_NAME_1).
+symbol(NO_NAME_1, "%0").
+symbol(NO_NAME_1, "1").
+symbol(NO_NAME_1, "2").
+symbol(NO_NAME_1, "3").
+symbol(NO_NAME_1, "4").
+symbol(NO_NAME_1, "5").
+symbol(NO_NAME_1, "6").
+symbol(NO_NAME_1, "7").
+symbol(NO_NAME_1, "8").
+symbol(NO_NAME_1, "9").
+arc(NO_NAME_1, 0, 1, "o":"y", 0.000000).
+arc(NO_NAME_1, 0, 2, "e":"y", 0.000000).
+arc(NO_NAME_1, 0, 3, "0":"k", 0.000000).
+arc(NO_NAME_1, 0, 4, "t":"k", 0.000000).
+arc(NO_NAME_1, 0, 5, "f":"n", 0.000000).
+arc(NO_NAME_1, 0, 6, "f":"v", 0.000000).
+arc(NO_NAME_1, 0, 7, "s":"k", 0.000000).
+arc(NO_NAME_1, 0, 8, "s", 0.000000).
+arc(NO_NAME_1, 0, 9, "e":"k", 0.000000).
+arc(NO_NAME_1, 0, 10, "n":"y", 0.000000).
+arc(NO_NAME_1, 1, 11, "0":"k", 0.000000).
+arc(NO_NAME_1, 2, 12, "0":"k", 0.000000).
+arc(NO_NAME_1, 3, 13, "t":"y", 0.000000).
+arc(NO_NAME_1, 4, 14, "0":"a", 0.000000).
+arc(NO_NAME_1, 4, 15, "0":"o", 0.000000).
+arc(NO_NAME_1, 5, 16, "0":"e", 0.000000).
+arc(NO_NAME_1, 6, 17, "0":"i", 0.000000).
+arc(NO_NAME_1, 7, 18, "0":"u", 0.000000).
+arc(NO_NAME_1, 8, 19, "0":"e", 0.000000).
+arc(NO_NAME_1, 9, 20, "0":"a", 0.000000).
+arc(NO_NAME_1, 10, 21, "0":"h", 0.000000).
+arc(NO_NAME_1, 11, 22, "0":"s", 0.000000).
+arc(NO_NAME_1, 12, 23, "0":"s", 0.000000).
+arc(NO_NAME_1, 13, 24, "0":"m", 0.000000).
+arc(NO_NAME_1, 14, 25, "0":"k", 0.000000).
+arc(NO_NAME_1, 15, 26, "0":"l", 0.000000).
+arc(NO_NAME_1, 16, 27, "0":"l", 0.000000).
+arc(NO_NAME_1, 17, 28, "0":"i", 0.000000).
+arc(NO_NAME_1, 18, 29, "0":"u", 0.000000).
+arc(NO_NAME_1, 19, 30, "0":"i", 0.000000).
+arc(NO_NAME_1, 20, 31, "0":"h", 0.000000).
+arc(NO_NAME_1, 21, 32, "0":"d", 0.000000).
+arc(NO_NAME_1, 22, 33, "0":"i", 0.000000).
+arc(NO_NAME_1, 23, 34, "0":"i", 0.000000).
+arc(NO_NAME_1, 24, 35, "0":"m", 0.000000).
+arc(NO_NAME_1, 25, 36, "0":"s", 0.000000).
+arc(NO_NAME_1, 26, 37, "0":"m", 0.000000).
+arc(NO_NAME_1, 27, 38, "0":"j", 0.000000).
+arc(NO_NAME_1, 28, 39, "0":"s", 0.000000).
+arc(NO_NAME_1, 29, 40, "0":"s", 0.000000).
+arc(NO_NAME_1, 30, 41, "0":"t", 0.000000).
+arc(NO_NAME_1, 31, 42, "0":"d", 0.000000).
+arc(NO_NAME_1, 32, 43, "0":"e", 0.000000).
+arc(NO_NAME_1, 33, 44, "n":"0", 0.000000).
+arc(NO_NAME_1, 34, 45, "0":"t", 0.000000).
+arc(NO_NAME_1, 35, 46, "0":"e", 0.000000).
+arc(NO_NAME_1, 36, 47, "0":"i", 0.000000).
+arc(NO_NAME_1, 37, 48, "0":"e", 0.000000).
+arc(NO_NAME_1, 38, 49, "0":"ä", 0.000000).
+arc(NO_NAME_1, 39, 50, "0":"i", 0.000000).
+arc(NO_NAME_1, 40, 51, "0":"i", 0.000000).
+arc(NO_NAME_1, 41, 52, "0":"s", 0.000000).
+arc(NO_NAME_1, 42, 53, "0":"e", 0.000000).
+arc(NO_NAME_1, 43, 54, "0":"k", 0.000000).
+arc(NO_NAME_1, 44, 55, "e":"0", 0.000000).
+arc(NO_NAME_1, 45, 56, "0":"o", 0.000000).
+arc(NO_NAME_1, 46, 57, "0":"n", 0.000000).
+arc(NO_NAME_1, 47, 58, "0":"k", 0.000000).
+arc(NO_NAME_1, 47, 59, "0":"t", 0.000000).
+arc(NO_NAME_1, 47, 60, "w":"0", 0.000000).
+arc(NO_NAME_1, 48, 61, "0":"k", 0.000000).
+arc(NO_NAME_1, 48, 62, "0":"t", 0.000000).
+arc(NO_NAME_1, 48, 63, "h":"0", 0.000000).
+arc(NO_NAME_1, 49, 64, "0":"k", 0.000000).
+arc(NO_NAME_1, 49, 65, "0":"t", 0.000000).
+arc(NO_NAME_1, 49, 66, "o":"0", 0.000000).
+arc(NO_NAME_1, 50, 67, "0":"k", 0.000000).
+arc(NO_NAME_1, 50, 68, "0":"t", 0.000000).
+arc(NO_NAME_1, 50, 69, "i":"0", 0.000000).
+arc(NO_NAME_1, 51, 70, "0":"k", 0.000000).
+arc(NO_NAME_1, 51, 71, "0":"t", 0.000000).
+arc(NO_NAME_1, 51, 72, "i":"0", 0.000000).
+arc(NO_NAME_1, 52, 73, "0":"e", 0.000000).
+arc(NO_NAME_1, 53, 74, "0":"k", 0.000000).
+arc(NO_NAME_1, 54, 75, "0":"s", 0.000000).
+arc(NO_NAME_1, 56, 76, "0":"i", 0.000000).
+arc(NO_NAME_1, 57, 77, "0":"e", 0.000000).
+arc(NO_NAME_1, 58, 78, "0":"y", 0.000000).
+arc(NO_NAME_1, 59, 79, "0":"o", 0.000000).
+arc(NO_NAME_1, 60, 55, "o":"0", 0.000000).
+arc(NO_NAME_1, 61, 80, "0":"y", 0.000000).
+arc(NO_NAME_1, 62, 81, "0":"o", 0.000000).
+arc(NO_NAME_1, 63, 82, "r":"0", 0.000000).
+arc(NO_NAME_1, 64, 83, "0":"y", 0.000000).
+arc(NO_NAME_1, 65, 84, "0":"o", 0.000000).
+arc(NO_NAME_1, 66, 85, "u":"0", 0.000000).
+arc(NO_NAME_1, 67, 86, "0":"y", 0.000000).
+arc(NO_NAME_1, 68, 87, "0":"o", 0.000000).
+arc(NO_NAME_1, 69, 44, "v":"0", 0.000000).
+arc(NO_NAME_1, 70, 88, "0":"y", 0.000000).
+arc(NO_NAME_1, 71, 89, "0":"o", 0.000000).
+arc(NO_NAME_1, 72, 55, "x":"0", 0.000000).
+arc(NO_NAME_1, 73, 90, "0":"m", 0.000000).
+arc(NO_NAME_1, 74, 91, "0":"s", 0.000000).
+arc(NO_NAME_1, 75, 92, "0":"ä", 0.000000).
+arc(NO_NAME_1, 76, 93, "0":"s", 0.000000).
+arc(NO_NAME_1, 77, 94, "0":"n", 0.000000).
+arc(NO_NAME_1, 78, 95, "0":"m", 0.000000).
+arc(NO_NAME_1, 79, 96, "0":"i", 0.000000).
+arc(NO_NAME_1, 80, 97, "0":"m", 0.000000).
+arc(NO_NAME_1, 81, 98, "0":"i", 0.000000).
+arc(NO_NAME_1, 82, 44, "e":"0", 0.000000).
+arc(NO_NAME_1, 83, 99, "0":"m", 0.000000).
+arc(NO_NAME_1, 84, 100, "0":"i", 0.000000).
+arc(NO_NAME_1, 85, 55, "r":"0", 0.000000).
+arc(NO_NAME_1, 86, 101, "0":"m", 0.000000).
+arc(NO_NAME_1, 87, 102, "0":"i", 0.000000).
+arc(NO_NAME_1, 88, 103, "0":"m", 0.000000).
+arc(NO_NAME_1, 89, 104, "0":"i", 0.000000).
+arc(NO_NAME_1, 90, 105, "0":"ä", 0.000000).
+arc(NO_NAME_1, 91, 106, "0":"a", 0.000000).
+arc(NO_NAME_1, 92, 107, "0":"n", 0.000000).
+arc(NO_NAME_1, 93, 108, "0":"t", 0.000000).
+arc(NO_NAME_1, 94, 109, "e":"0", 0.000000).
+arc(NO_NAME_1, 95, 110, "0":"m", 0.000000).
+arc(NO_NAME_1, 96, 111, "0":"s", 0.000000).
+arc(NO_NAME_1, 97, 112, "0":"m", 0.000000).
+arc(NO_NAME_1, 98, 113, "0":"s", 0.000000).
+arc(NO_NAME_1, 99, 114, "0":"m", 0.000000).
+arc(NO_NAME_1, 100, 115, "0":"s", 0.000000).
+arc(NO_NAME_1, 101, 116, "0":"m", 0.000000).
+arc(NO_NAME_1, 102, 117, "0":"s", 0.000000).
+arc(NO_NAME_1, 103, 118, "0":"m", 0.000000).
+arc(NO_NAME_1, 104, 119, "0":"s", 0.000000).
+arc(NO_NAME_1, 105, 120, "0":"n", 0.000000).
+arc(NO_NAME_1, 106, 121, "0":"n", 0.000000).
+arc(NO_NAME_1, 107, 122, "0":"k", 0.000000).
+arc(NO_NAME_1, 107, 123, "0":"t", 0.000000).
+arc(NO_NAME_1, 107, 33, "i":"0", 0.000000).
+arc(NO_NAME_1, 108, 124, "0":"a", 0.000000).
+arc(NO_NAME_1, 109, 55, "n":"0", 0.000000).
+arc(NO_NAME_1, 110, 125, "0":"e", 0.000000).
+arc(NO_NAME_1, 111, 126, "0":"t", 0.000000).
+arc(NO_NAME_1, 112, 127, "0":"e", 0.000000).
+arc(NO_NAME_1, 113, 128, "0":"t", 0.000000).
+arc(NO_NAME_1, 114, 129, "0":"e", 0.000000).
+arc(NO_NAME_1, 115, 130, "0":"t", 0.000000).
+arc(NO_NAME_1, 116, 131, "0":"e", 0.000000).
+arc(NO_NAME_1, 117, 132, "0":"t", 0.000000).
+arc(NO_NAME_1, 118, 133, "0":"e", 0.000000).
+arc(NO_NAME_1, 119, 134, "0":"t", 0.000000).
+arc(NO_NAME_1, 120, 135, "0":"k", 0.000000).
+arc(NO_NAME_1, 120, 136, "0":"t", 0.000000).
+arc(NO_NAME_1, 120, 137, "e":"0", 0.000000).
+arc(NO_NAME_1, 121, 138, "0":"k", 0.000000).
+arc(NO_NAME_1, 121, 139, "0":"t", 0.000000).
+arc(NO_NAME_1, 121, 140, "i":"0", 0.000000).
+arc(NO_NAME_1, 122, 141, "0":"y", 0.000000).
+arc(NO_NAME_1, 123, 142, "0":"o", 0.000000).
+arc(NO_NAME_1, 124, 143, "l":"0", 0.000000).
+arc(NO_NAME_1, 125, 144, "0":"n", 0.000000).
+arc(NO_NAME_1, 126, 145, "0":"a", 0.000000).
+arc(NO_NAME_1, 127, 146, "0":"n", 0.000000).
+arc(NO_NAME_1, 128, 147, "0":"a", 0.000000).
+arc(NO_NAME_1, 129, 148, "0":"n", 0.000000).
+arc(NO_NAME_1, 130, 149, "0":"a", 0.000000).
+arc(NO_NAME_1, 131, 150, "0":"n", 0.000000).
+arc(NO_NAME_1, 132, 151, "0":"a", 0.000000).
+arc(NO_NAME_1, 133, 152, "0":"n", 0.000000).
+arc(NO_NAME_1, 134, 153, "0":"a", 0.000000).
+arc(NO_NAME_1, 135, 154, "0":"y", 0.000000).
+arc(NO_NAME_1, 136, 155, "0":"o", 0.000000).
+arc(NO_NAME_1, 137, 94, "v":"0", 0.000000).
+arc(NO_NAME_1, 138, 156, "0":"y", 0.000000).
+arc(NO_NAME_1, 139, 157, "0":"o", 0.000000).
+arc(NO_NAME_1, 140, 158, "g":"0", 0.000000).
+arc(NO_NAME_1, 141, 159, "0":"m", 0.000000).
+arc(NO_NAME_1, 142, 160, "0":"i", 0.000000).
+arc(NO_NAME_1, 143, 137, "e":"0", 0.000000).
+arc(NO_NAME_1, 144, 161, "0":"t", 0.000000).
+arc(NO_NAME_1, 145, 162, "w":"0", 0.000000).
+arc(NO_NAME_1, 146, 163, "0":"t", 0.000000).
+arc(NO_NAME_1, 147, 164, "h":"0", 0.000000).
+arc(NO_NAME_1, 148, 165, "0":"t", 0.000000).
+arc(NO_NAME_1, 149, 166, "o":"0", 0.000000).
+arc(NO_NAME_1, 150, 167, "0":"t", 0.000000).
+arc(NO_NAME_1, 151, 168, "i":"0", 0.000000).
+arc(NO_NAME_1, 152, 169, "0":"t", 0.000000).
+arc(NO_NAME_1, 153, 170, "i":"0", 0.000000).
+arc(NO_NAME_1, 154, 171, "0":"m", 0.000000).
+arc(NO_NAME_1, 155, 172, "0":"i", 0.000000).
+arc(NO_NAME_1, 156, 173, "0":"m", 0.000000).
+arc(NO_NAME_1, 157, 174, "0":"i", 0.000000).
+arc(NO_NAME_1, 158, 175, "h":"0", 0.000000).
+arc(NO_NAME_1, 159, 176, "0":"m", 0.000000).
+arc(NO_NAME_1, 160, 177, "0":"s", 0.000000).
+arc(NO_NAME_1, 161, 178, "0":"ä", 0.000000).
+arc(NO_NAME_1, 162, 179, "e":"0", 0.000000).
+arc(NO_NAME_1, 163, 180, "0":"ä", 0.000000).
+arc(NO_NAME_1, 164, 181, "i":"0", 0.000000).
+arc(NO_NAME_1, 165, 182, "0":"ä", 0.000000).
+arc(NO_NAME_1, 166, 181, "u":"0", 0.000000).
+arc(NO_NAME_1, 167, 183, "0":"ä", 0.000000).
+arc(NO_NAME_1, 168, 184, "f":"0", 0.000000).
+arc(NO_NAME_1, 169, 185, "0":"ä", 0.000000).
+arc(NO_NAME_1, 170, 184, "x":"0", 0.000000).
+arc(NO_NAME_1, 171, 186, "0":"m", 0.000000).
+arc(NO_NAME_1, 172, 187, "0":"s", 0.000000).
+arc(NO_NAME_1, 173, 188, "0":"m", 0.000000).
+arc(NO_NAME_1, 174, 189, "0":"s", 0.000000).
+arc(NO_NAME_1, 175, 55, "t":"0", 0.000000).
+arc(NO_NAME_1, 176, 190, "0":"e", 0.000000).
+arc(NO_NAME_1, 177, 191, "0":"t", 0.000000).
+arc(NO_NAME_1, 178, 192, "w":"0", 0.000000).
+arc(NO_NAME_1, 179, 69, "l":"0", 0.000000).
+arc(NO_NAME_1, 180, 193, "h":"0", 0.000000).
+arc(NO_NAME_1, 181, 184, "r":"0", 0.000000).
+arc(NO_NAME_1, 182, 194, "o":"0", 0.000000).
+arc(NO_NAME_1, 183, 195, "i":"0", 0.000000).
+arc(NO_NAME_1, 184, 196, "t":"0", 0.000000).
+arc(NO_NAME_1, 185, 197, "i":"0", 0.000000).
+arc(NO_NAME_1, 186, 198, "0":"e", 0.000000).
+arc(NO_NAME_1, 187, 199, "0":"t", 0.000000).
+arc(NO_NAME_1, 188, 200, "0":"e", 0.000000).
+arc(NO_NAME_1, 189, 201, "0":"t", 0.000000).
+arc(NO_NAME_1, 190, 202, "0":"n", 0.000000).
+arc(NO_NAME_1, 191, 203, "0":"a", 0.000000).
+arc(NO_NAME_1, 192, 204, "e":"0", 0.000000).
+arc(NO_NAME_1, 193, 194, "i":"0", 0.000000).
+arc(NO_NAME_1, 194, 205, "r":"0", 0.000000).
+arc(NO_NAME_1, 195, 205, "f":"0", 0.000000).
+arc(NO_NAME_1, 196, 94, "e":"0", 0.000000).
+arc(NO_NAME_1, 197, 205, "x":"0", 0.000000).
+arc(NO_NAME_1, 198, 206, "0":"n", 0.000000).
+arc(NO_NAME_1, 199, 207, "0":"a", 0.000000).
+arc(NO_NAME_1, 200, 208, "0":"n", 0.000000).
+arc(NO_NAME_1, 201, 209, "0":"a", 0.000000).
+arc(NO_NAME_1, 202, 210, "0":"t", 0.000000).
+arc(NO_NAME_1, 203, 211, "i":"0", 0.000000).
+arc(NO_NAME_1, 204, 205, "n":"0", 0.000000).
+arc(NO_NAME_1, 205, 212, "t":"0", 0.000000).
+arc(NO_NAME_1, 206, 213, "0":"t", 0.000000).
+arc(NO_NAME_1, 207, 214, "e":"0", 0.000000).
+arc(NO_NAME_1, 208, 215, "0":"t", 0.000000).
+arc(NO_NAME_1, 209, 216, "i":"0", 0.000000).
+arc(NO_NAME_1, 210, 217, "0":"ä", 0.000000).
+arc(NO_NAME_1, 211, 218, "n":"0", 0.000000).
+arc(NO_NAME_1, 212, 219, "y":"0", 0.000000).
+arc(NO_NAME_1, 213, 220, "0":"ä", 0.000000).
+arc(NO_NAME_1, 214, 221, "v":"0", 0.000000).
+arc(NO_NAME_1, 215, 222, "0":"ä", 0.000000).
+arc(NO_NAME_1, 216, 223, "g":"0", 0.000000).
+arc(NO_NAME_1, 217, 224, "i":"0", 0.000000).
+arc(NO_NAME_1, 218, 184, "e":"0", 0.000000).
+arc(NO_NAME_1, 219, 225, "-":"0", 0.000000).
+arc(NO_NAME_1, 220, 226, "e":"0", 0.000000).
+arc(NO_NAME_1, 221, 227, "e":"0", 0.000000).
+arc(NO_NAME_1, 222, 228, "i":"0", 0.000000).
+arc(NO_NAME_1, 223, 184, "h":"0", 0.000000).
+arc(NO_NAME_1, 224, 229, "n":"0", 0.000000).
+arc(NO_NAME_1, 225, 1, "o":"y", 0.000000).
+arc(NO_NAME_1, 225, 230, "t":"k", 0.000000).
+arc(NO_NAME_1, 225, 231, "f":"n", 0.000000).
+arc(NO_NAME_1, 225, 232, "f":"v", 0.000000).
+arc(NO_NAME_1, 225, 233, "s":"k", 0.000000).
+arc(NO_NAME_1, 225, 234, "s", 0.000000).
+arc(NO_NAME_1, 225, 235, "e":"k", 0.000000).
+arc(NO_NAME_1, 225, 236, "n":"y", 0.000000).
+arc(NO_NAME_1, 226, 192, "v":"0", 0.000000).
+arc(NO_NAME_1, 227, 184, "n":"0", 0.000000).
+arc(NO_NAME_1, 228, 237, "g":"0", 0.000000).
+arc(NO_NAME_1, 229, 205, "e":"0", 0.000000).
+arc(NO_NAME_1, 230, 238, "0":"a", 0.000000).
+arc(NO_NAME_1, 230, 239, "0":"o", 0.000000).
+arc(NO_NAME_1, 231, 240, "0":"e", 0.000000).
+arc(NO_NAME_1, 232, 241, "0":"i", 0.000000).
+arc(NO_NAME_1, 233, 242, "0":"u", 0.000000).
+arc(NO_NAME_1, 234, 243, "0":"e", 0.000000).
+arc(NO_NAME_1, 235, 244, "0":"a", 0.000000).
+arc(NO_NAME_1, 236, 245, "0":"h", 0.000000).
+arc(NO_NAME_1, 237, 205, "h":"0", 0.000000).
+arc(NO_NAME_1, 238, 246, "0":"k", 0.000000).
+arc(NO_NAME_1, 239, 247, "0":"l", 0.000000).
+arc(NO_NAME_1, 240, 248, "0":"l", 0.000000).
+arc(NO_NAME_1, 241, 249, "0":"i", 0.000000).
+arc(NO_NAME_1, 242, 250, "0":"u", 0.000000).
+arc(NO_NAME_1, 243, 251, "0":"i", 0.000000).
+arc(NO_NAME_1, 244, 252, "0":"h", 0.000000).
+arc(NO_NAME_1, 245, 253, "0":"d", 0.000000).
+arc(NO_NAME_1, 246, 254, "0":"s", 0.000000).
+arc(NO_NAME_1, 247, 255, "0":"m", 0.000000).
+arc(NO_NAME_1, 248, 256, "0":"j", 0.000000).
+arc(NO_NAME_1, 249, 257, "0":"s", 0.000000).
+arc(NO_NAME_1, 250, 258, "0":"s", 0.000000).
+arc(NO_NAME_1, 251, 259, "0":"t", 0.000000).
+arc(NO_NAME_1, 252, 260, "0":"d", 0.000000).
+arc(NO_NAME_1, 253, 261, "0":"e", 0.000000).
+arc(NO_NAME_1, 254, 262, "0":"i", 0.000000).
+arc(NO_NAME_1, 255, 263, "0":"e", 0.000000).
+arc(NO_NAME_1, 256, 264, "0":"ä", 0.000000).
+arc(NO_NAME_1, 257, 265, "0":"i", 0.000000).
+arc(NO_NAME_1, 258, 266, "0":"i", 0.000000).
+arc(NO_NAME_1, 259, 267, "0":"s", 0.000000).
+arc(NO_NAME_1, 260, 268, "0":"e", 0.000000).
+arc(NO_NAME_1, 261, 269, "0":"k", 0.000000).
+arc(NO_NAME_1, 262, 60, "w":"0", 0.000000).
+arc(NO_NAME_1, 263, 63, "h":"0", 0.000000).
+arc(NO_NAME_1, 264, 66, "o":"0", 0.000000).
+arc(NO_NAME_1, 265, 69, "i":"0", 0.000000).
+arc(NO_NAME_1, 266, 72, "i":"0", 0.000000).
+arc(NO_NAME_1, 267, 270, "0":"e", 0.000000).
+arc(NO_NAME_1, 268, 271, "0":"k", 0.000000).
+arc(NO_NAME_1, 269, 272, "0":"s", 0.000000).
+arc(NO_NAME_1, 270, 273, "0":"m", 0.000000).
+arc(NO_NAME_1, 271, 274, "0":"s", 0.000000).
+arc(NO_NAME_1, 272, 275, "0":"ä", 0.000000).
+arc(NO_NAME_1, 273, 276, "0":"ä", 0.000000).
+arc(NO_NAME_1, 274, 277, "0":"a", 0.000000).
+arc(NO_NAME_1, 275, 278, "0":"n", 0.000000).
+arc(NO_NAME_1, 276, 143, "0":"n", 0.000000).
+arc(NO_NAME_1, 277, 279, "0":"n", 0.000000).
+arc(NO_NAME_1, 278, 33, "i":"0", 0.000000).
+arc(NO_NAME_1, 279, 140, "i":"0", 0.000000).
+final(NO_NAME_1, 55, 0.000000).
+final(NO_NAME_1, 219, 0.000000).
diff --git a/test/tools/fsmbook-tests/expected-results/FinnishProsody.prolog b/test/tools/fsmbook-tests/expected-results/FinnishProsody.prolog
new file mode 100644
index 0000000..89022f0
--- /dev/null
+++ b/test/tools/fsmbook-tests/expected-results/FinnishProsody.prolog
@@ -0,0 +1,532 @@
+network(NO_NAME_1).
+symbol(NO_NAME_1, "b").
+symbol(NO_NAME_1, "c").
+symbol(NO_NAME_1, "f").
+symbol(NO_NAME_1, "q").
+symbol(NO_NAME_1, "w").
+symbol(NO_NAME_1, "x").
+symbol(NO_NAME_1, "z").
+symbol(NO_NAME_1, "ö´").
+symbol(NO_NAME_1, "ý").
+arc(NO_NAME_1, 0, 1, "0":"(", 0.000000).
+arc(NO_NAME_1, 0, 2, "0":"(", 0.000000).
+arc(NO_NAME_1, 1, 3, "k", 0.000000).
+arc(NO_NAME_1, 1, 4, "s", 0.000000).
+arc(NO_NAME_1, 1, 5, "m", 0.000000).
+arc(NO_NAME_1, 1, 6, "o":"ó", 0.000000).
+arc(NO_NAME_1, 1, 7, "r", 0.000000).
+arc(NO_NAME_1, 1, 8, "v", 0.000000).
+arc(NO_NAME_1, 1, 9, "p", 0.000000).
+arc(NO_NAME_1, 2, 10, "k", 0.000000).
+arc(NO_NAME_1, 2, 11, "e":"é", 0.000000).
+arc(NO_NAME_1, 2, 12, "m", 0.000000).
+arc(NO_NAME_1, 2, 13, "i":"í", 0.000000).
+arc(NO_NAME_1, 2, 14, "o":"ó", 0.000000).
+arc(NO_NAME_1, 2, 15, "j", 0.000000).
+arc(NO_NAME_1, 2, 16, "r", 0.000000).
+arc(NO_NAME_1, 3, 17, "a":"á", 0.000000).
+arc(NO_NAME_1, 4, 18, "t", 0.000000).
+arc(NO_NAME_1, 5, 19, "a":"á", 0.000000).
+arc(NO_NAME_1, 6, 20, "0":".", 0.000000).
+arc(NO_NAME_1, 7, 21, "a":"á", 0.000000).
+arc(NO_NAME_1, 8, 22, "o":"ó", 0.000000).
+arc(NO_NAME_1, 9, 23, "e":"é", 0.000000).
+arc(NO_NAME_1, 9, 24, "u":"ú", 0.000000).
+arc(NO_NAME_1, 10, 25, "a":"á", 0.000000).
+arc(NO_NAME_1, 10, 26, "u":"ú", 0.000000).
+arc(NO_NAME_1, 11, 27, "r", 0.000000).
+arc(NO_NAME_1, 12, 28, "e":"é", 0.000000).
+arc(NO_NAME_1, 12, 29, "ä":"ä´", 0.000000).
+arc(NO_NAME_1, 13, 30, "l", 0.000000).
+arc(NO_NAME_1, 14, 31, "0":".", 0.000000).
+arc(NO_NAME_1, 14, 32, "n", 0.000000).
+arc(NO_NAME_1, 15, 33, "ä":"ä´", 0.000000).
+arc(NO_NAME_1, 16, 34, "a":"á", 0.000000).
+arc(NO_NAME_1, 16, 35, "e":"é", 0.000000).
+arc(NO_NAME_1, 17, 36, "0":".", 0.000000).
+arc(NO_NAME_1, 18, 37, "r", 0.000000).
+arc(NO_NAME_1, 19, 38, "0":".", 0.000000).
+arc(NO_NAME_1, 20, 39, "p", 0.000000).
+arc(NO_NAME_1, 21, 40, "0":".", 0.000000).
+arc(NO_NAME_1, 22, 41, "i", 0.000000).
+arc(NO_NAME_1, 23, 42, "0":".", 0.000000).
+arc(NO_NAME_1, 24, 43, "0":".", 0.000000).
+arc(NO_NAME_1, 25, 44, "0":".", 0.000000).
+arc(NO_NAME_1, 25, 45, "i", 0.000000).
+arc(NO_NAME_1, 26, 46, "0":".", 0.000000).
+arc(NO_NAME_1, 27, 47, "0":".", 0.000000).
+arc(NO_NAME_1, 28, 48, "r", 0.000000).
+arc(NO_NAME_1, 29, 49, "0":".", 0.000000).
+arc(NO_NAME_1, 30, 50, "0":".", 0.000000).
+arc(NO_NAME_1, 31, 51, "p", 0.000000).
+arc(NO_NAME_1, 32, 52, "0":".", 0.000000).
+arc(NO_NAME_1, 33, 53, "r", 0.000000).
+arc(NO_NAME_1, 34, 54, "0":".", 0.000000).
+arc(NO_NAME_1, 35, 55, "0":".", 0.000000).
+arc(NO_NAME_1, 36, 56, "l", 0.000000).
+arc(NO_NAME_1, 37, 57, "u":"ú", 0.000000).
+arc(NO_NAME_1, 38, 58, "t", 0.000000).
+arc(NO_NAME_1, 39, 59, "e", 0.000000).
+arc(NO_NAME_1, 40, 60, "k", 0.000000).
+arc(NO_NAME_1, 41, 61, "0":".", 0.000000).
+arc(NO_NAME_1, 42, 62, "r", 0.000000).
+arc(NO_NAME_1, 43, 63, "h", 0.000000).
+arc(NO_NAME_1, 44, 64, "l", 0.000000).
+arc(NO_NAME_1, 45, 65, "0":".", 0.000000).
+arc(NO_NAME_1, 46, 66, "n", 0.000000).
+arc(NO_NAME_1, 47, 67, "g", 0.000000).
+arc(NO_NAME_1, 48, 68, "0":".", 0.000000).
+arc(NO_NAME_1, 49, 69, "k", 0.000000).
+arc(NO_NAME_1, 50, 70, "m", 0.000000).
+arc(NO_NAME_1, 51, 71, "i", 0.000000).
+arc(NO_NAME_1, 52, 72, "n", 0.000000).
+arc(NO_NAME_1, 53, 73, "0":".", 0.000000).
+arc(NO_NAME_1, 54, 74, "v", 0.000000).
+arc(NO_NAME_1, 55, 75, "p", 0.000000).
+arc(NO_NAME_1, 56, 76, "a", 0.000000).
+arc(NO_NAME_1, 57, 77, "k", 0.000000).
+arc(NO_NAME_1, 58, 78, "e", 0.000000).
+arc(NO_NAME_1, 59, 79, "t", 0.000000).
+arc(NO_NAME_1, 60, 80, "a", 0.000000).
+arc(NO_NAME_1, 61, 81, "m", 0.000000).
+arc(NO_NAME_1, 62, 82, "i", 0.000000).
+arc(NO_NAME_1, 63, 83, "e", 0.000000).
+arc(NO_NAME_1, 64, 84, "a", 0.000000).
+arc(NO_NAME_1, 65, 85, "n", 0.000000).
+arc(NO_NAME_1, 66, 86, "i", 0.000000).
+arc(NO_NAME_1, 67, 87, "o", 0.000000).
+arc(NO_NAME_1, 68, 88, "k", 0.000000).
+arc(NO_NAME_1, 69, 89, "i", 0.000000).
+arc(NO_NAME_1, 70, 90, "o", 0.000000).
+arc(NO_NAME_1, 71, 91, "s", 0.000000).
+arc(NO_NAME_1, 72, 92, "i", 0.000000).
+arc(NO_NAME_1, 73, 93, "j", 0.000000).
+arc(NO_NAME_1, 74, 94, "i", 0.000000).
+arc(NO_NAME_1, 75, 95, "e", 0.000000).
+arc(NO_NAME_1, 76, 96, "s", 0.000000).
+arc(NO_NAME_1, 77, 97, "0":".", 0.000000).
+arc(NO_NAME_1, 78, 98, "0":".", 0.000000).
+arc(NO_NAME_1, 79, 99, "0":".", 0.000000).
+arc(NO_NAME_1, 80, 100, "s", 0.000000).
+arc(NO_NAME_1, 81, 101, "i", 0.000000).
+arc(NO_NAME_1, 82, 102, "0":".", 0.000000).
+arc(NO_NAME_1, 83, 103, "0":".", 0.000000).
+arc(NO_NAME_1, 84, 104, "s", 0.000000).
+arc(NO_NAME_1, 85, 105, "o", 0.000000).
+arc(NO_NAME_1, 86, 106, "n", 0.000000).
+arc(NO_NAME_1, 87, 107, "0":")", 0.000000).
+arc(NO_NAME_1, 88, 108, "o", 0.000000).
+arc(NO_NAME_1, 89, 109, "0":")", 0.000000).
+arc(NO_NAME_1, 90, 110, "i", 0.000000).
+arc(NO_NAME_1, 91, 111, "0":")", 0.000000).
+arc(NO_NAME_1, 92, 112, "t", 0.000000).
+arc(NO_NAME_1, 93, 113, "e", 0.000000).
+arc(NO_NAME_1, 94, 114, "n", 0.000000).
+arc(NO_NAME_1, 95, 115, "0":")", 0.000000).
+arc(NO_NAME_1, 96, 116, "0":".", 0.000000).
+arc(NO_NAME_1, 97, 117, "t", 0.000000).
+arc(NO_NAME_1, 98, 118, "m", 0.000000).
+arc(NO_NAME_1, 99, 119, "t", 0.000000).
+arc(NO_NAME_1, 100, 120, "0":".", 0.000000).
+arc(NO_NAME_1, 101, 121, "s", 0.000000).
+arc(NO_NAME_1, 102, 122, "j", 0.000000).
+arc(NO_NAME_1, 103, 123, "l", 0.000000).
+arc(NO_NAME_1, 104, 124, "0":")", 0.000000).
+arc(NO_NAME_1, 105, 125, "s", 0.000000).
+arc(NO_NAME_1, 106, 126, "0":")", 0.000000).
+arc(NO_NAME_1, 107, 127, "0":".", 0.000000).
+arc(NO_NAME_1, 108, 128, "0":")", 0.000000).
+arc(NO_NAME_1, 110, 129, "t", 0.000000).
+arc(NO_NAME_1, 111, 130, "0":".", 0.000000).
+arc(NO_NAME_1, 112, 131, "0":")", 0.000000).
+arc(NO_NAME_1, 113, 132, "s", 0.000000).
+arc(NO_NAME_1, 114, 133, "0":")", 0.000000).
+arc(NO_NAME_1, 115, 134, "0":".", 0.000000).
+arc(NO_NAME_1, 116, 135, "t", 0.000000).
+arc(NO_NAME_1, 117, 136, "u", 0.000000).
+arc(NO_NAME_1, 118, 137, "a", 0.000000).
+arc(NO_NAME_1, 119, 138, "a", 0.000000).
+arc(NO_NAME_1, 120, 139, "t", 0.000000).
+arc(NO_NAME_1, 121, 140, "0":".", 0.000000).
+arc(NO_NAME_1, 122, 141, "ä", 0.000000).
+arc(NO_NAME_1, 123, 142, "i", 0.000000).
+arc(NO_NAME_1, 124, 143, "0":".", 0.000000).
+arc(NO_NAME_1, 125, 144, "0":")", 0.000000).
+arc(NO_NAME_1, 126, 145, "0":".", 0.000000).
+arc(NO_NAME_1, 127, 146, "0":"(", 0.000000).
+arc(NO_NAME_1, 128, 147, "0":".", 0.000000).
+arc(NO_NAME_1, 129, 148, "0":")", 0.000000).
+arc(NO_NAME_1, 130, 149, "0":"(", 0.000000).
+arc(NO_NAME_1, 131, 150, "0":".", 0.000000).
+arc(NO_NAME_1, 132, 151, "0":")", 0.000000).
+arc(NO_NAME_1, 133, 152, "0":".", 0.000000).
+arc(NO_NAME_1, 134, 153, "0":"(", 0.000000).
+arc(NO_NAME_1, 135, 154, "e", 0.000000).
+arc(NO_NAME_1, 136, 155, "0":".", 0.000000).
+arc(NO_NAME_1, 137, 156, "0":")", 0.000000).
+arc(NO_NAME_1, 138, 157, "0":")", 0.000000).
+arc(NO_NAME_1, 139, 158, "a", 0.000000).
+arc(NO_NAME_1, 140, 159, "t", 0.000000).
+arc(NO_NAME_1, 141, 160, "0":")", 0.000000).
+arc(NO_NAME_1, 142, 161, "0":")", 0.000000).
+arc(NO_NAME_1, 143, 162, "0":"(", 0.000000).
+arc(NO_NAME_1, 144, 163, "0":".", 0.000000).
+arc(NO_NAME_1, 145, 164, "g", 0.000000).
+arc(NO_NAME_1, 146, 165, "n", 0.000000).
+arc(NO_NAME_1, 147, 166, "0":"(", 0.000000).
+arc(NO_NAME_1, 148, 167, "0":".", 0.000000).
+arc(NO_NAME_1, 149, 168, "k", 0.000000).
+arc(NO_NAME_1, 150, 169, "0":"(", 0.000000).
+arc(NO_NAME_1, 151, 170, "0":".", 0.000000).
+arc(NO_NAME_1, 152, 171, "0":"(", 0.000000).
+arc(NO_NAME_1, 153, 172, "ä":"ä`", 0.000000).
+arc(NO_NAME_1, 154, 173, "0":")", 0.000000).
+arc(NO_NAME_1, 155, 174, "r", 0.000000).
+arc(NO_NAME_1, 156, 175, "0":".", 0.000000).
+arc(NO_NAME_1, 157, 176, "0":".", 0.000000).
+arc(NO_NAME_1, 158, 177, "0":")", 0.000000).
+arc(NO_NAME_1, 159, 178, "e", 0.000000).
+arc(NO_NAME_1, 161, 179, "0":".", 0.000000).
+arc(NO_NAME_1, 162, 180, "t", 0.000000).
+arc(NO_NAME_1, 163, 181, "0":"(", 0.000000).
+arc(NO_NAME_1, 164, 182, "a", 0.000000).
+arc(NO_NAME_1, 164, 183, "a":"à", 0.000000).
+arc(NO_NAME_1, 165, 184, "o":"ò", 0.000000).
+arc(NO_NAME_1, 166, 185, "n", 0.000000).
+arc(NO_NAME_1, 167, 186, "0":"(", 0.000000).
+arc(NO_NAME_1, 167, 187, "0":"(", 0.000000).
+arc(NO_NAME_1, 168, 188, "e":"è", 0.000000).
+arc(NO_NAME_1, 169, 189, "t", 0.000000).
+arc(NO_NAME_1, 170, 190, "0":"(", 0.000000).
+arc(NO_NAME_1, 170, 191, "0":"(", 0.000000).
+arc(NO_NAME_1, 171, 192, "t", 0.000000).
+arc(NO_NAME_1, 172, 193, "0":".", 0.000000).
+arc(NO_NAME_1, 173, 194, "0":".", 0.000000).
+arc(NO_NAME_1, 174, 195, "a", 0.000000).
+arc(NO_NAME_1, 175, 196, "0":"(", 0.000000).
+arc(NO_NAME_1, 176, 197, "0":"(", 0.000000).
+arc(NO_NAME_1, 177, 198, "0":".", 0.000000).
+arc(NO_NAME_1, 178, 199, "0":")", 0.000000).
+arc(NO_NAME_1, 179, 200, "0":"(", 0.000000).
+arc(NO_NAME_1, 180, 201, "e":"è", 0.000000).
+arc(NO_NAME_1, 181, 202, "t", 0.000000).
+arc(NO_NAME_1, 182, 203, "s", 0.000000).
+arc(NO_NAME_1, 183, 204, "s", 0.000000).
+arc(NO_NAME_1, 184, 205, "0":".", 0.000000).
+arc(NO_NAME_1, 185, 206, "o":"ò", 0.000000).
+arc(NO_NAME_1, 186, 207, "t", 0.000000).
+arc(NO_NAME_1, 187, 208, "t", 0.000000).
+arc(NO_NAME_1, 188, 209, "0":".", 0.000000).
+arc(NO_NAME_1, 189, 210, "e":"è", 0.000000).
+arc(NO_NAME_1, 190, 211, "t", 0.000000).
+arc(NO_NAME_1, 191, 212, "t", 0.000000).
+arc(NO_NAME_1, 192, 213, "o":"ò", 0.000000).
+arc(NO_NAME_1, 193, 214, "m", 0.000000).
+arc(NO_NAME_1, 194, 215, "0":"(", 0.000000).
+arc(NO_NAME_1, 195, 216, "0":")", 0.000000).
+arc(NO_NAME_1, 196, 217, "t", 0.000000).
+arc(NO_NAME_1, 197, 218, "m", 0.000000).
+arc(NO_NAME_1, 198, 219, "0":"(", 0.000000).
+arc(NO_NAME_1, 199, 220, "0":".", 0.000000).
+arc(NO_NAME_1, 200, 221, "m", 0.000000).
+arc(NO_NAME_1, 201, 222, "0":".", 0.000000).
+arc(NO_NAME_1, 202, 223, "e":"è", 0.000000).
+arc(NO_NAME_1, 205, 224, "m", 0.000000).
+arc(NO_NAME_1, 206, 225, "0":".", 0.000000).
+arc(NO_NAME_1, 207, 226, "a":"à", 0.000000).
+arc(NO_NAME_1, 208, 227, "a":"à", 0.000000).
+arc(NO_NAME_1, 209, 228, "l", 0.000000).
+arc(NO_NAME_1, 210, 229, "0":".", 0.000000).
+arc(NO_NAME_1, 211, 230, "e":"è", 0.000000).
+arc(NO_NAME_1, 212, 231, "e":"è", 0.000000).
+arc(NO_NAME_1, 213, 232, "0":".", 0.000000).
+arc(NO_NAME_1, 214, 233, "ä", 0.000000).
+arc(NO_NAME_1, 215, 234, "l", 0.000000).
+arc(NO_NAME_1, 216, 235, "0":".", 0.000000).
+arc(NO_NAME_1, 217, 236, "i":"ì", 0.000000).
+arc(NO_NAME_1, 218, 237, "a":"à", 0.000000).
+arc(NO_NAME_1, 219, 238, "j", 0.000000).
+arc(NO_NAME_1, 220, 239, "0":"(", 0.000000).
+arc(NO_NAME_1, 221, 240, "e":"è", 0.000000).
+arc(NO_NAME_1, 221, 241, "i":"ì", 0.000000).
+arc(NO_NAME_1, 222, 242, "l", 0.000000).
+arc(NO_NAME_1, 223, 243, "0":".", 0.000000).
+arc(NO_NAME_1, 224, 244, "i", 0.000000).
+arc(NO_NAME_1, 225, 245, "m", 0.000000).
+arc(NO_NAME_1, 226, 246, "u", 0.000000).
+arc(NO_NAME_1, 227, 247, "u", 0.000000).
+arc(NO_NAME_1, 228, 248, "i", 0.000000).
+arc(NO_NAME_1, 229, 249, "l", 0.000000).
+arc(NO_NAME_1, 230, 250, "l", 0.000000).
+arc(NO_NAME_1, 231, 251, "0":".", 0.000000).
+arc(NO_NAME_1, 231, 252, "l", 0.000000).
+arc(NO_NAME_1, 232, 253, "l", 0.000000).
+arc(NO_NAME_1, 233, 254, "0":")", 0.000000).
+arc(NO_NAME_1, 234, 255, "e":"è", 0.000000).
+arc(NO_NAME_1, 235, 256, "0":"(", 0.000000).
+arc(NO_NAME_1, 236, 257, "i", 0.000000).
+arc(NO_NAME_1, 237, 258, "s", 0.000000).
+arc(NO_NAME_1, 238, 259, "a":"à", 0.000000).
+arc(NO_NAME_1, 239, 260, "l", 0.000000).
+arc(NO_NAME_1, 240, 261, "l", 0.000000).
+arc(NO_NAME_1, 241, 262, "s", 0.000000).
+arc(NO_NAME_1, 242, 263, "e", 0.000000).
+arc(NO_NAME_1, 243, 264, "l", 0.000000).
+arc(NO_NAME_1, 244, 265, "0":".", 0.000000).
+arc(NO_NAME_1, 245, 266, "i", 0.000000).
+arc(NO_NAME_1, 246, 267, "0":".", 0.000000).
+arc(NO_NAME_1, 247, 268, "0":".", 0.000000).
+arc(NO_NAME_1, 248, 269, "0":".", 0.000000).
+arc(NO_NAME_1, 249, 270, "e", 0.000000).
+arc(NO_NAME_1, 250, 271, "0":".", 0.000000).
+arc(NO_NAME_1, 251, 272, "l", 0.000000).
+arc(NO_NAME_1, 252, 273, "0":".", 0.000000).
+arc(NO_NAME_1, 253, 274, "a", 0.000000).
+arc(NO_NAME_1, 255, 275, "m", 0.000000).
+arc(NO_NAME_1, 256, 276, "l", 0.000000).
+arc(NO_NAME_1, 257, 277, "k", 0.000000).
+arc(NO_NAME_1, 258, 278, "0":".", 0.000000).
+arc(NO_NAME_1, 259, 279, "t", 0.000000).
+arc(NO_NAME_1, 260, 280, "u":"ù", 0.000000).
+arc(NO_NAME_1, 261, 281, "0":".", 0.000000).
+arc(NO_NAME_1, 262, 282, "0":".", 0.000000).
+arc(NO_NAME_1, 263, 283, "0":")", 0.000000).
+arc(NO_NAME_1, 263, 284, "t", 0.000000).
+arc(NO_NAME_1, 264, 285, "i", 0.000000).
+arc(NO_NAME_1, 265, 286, "a", 0.000000).
+arc(NO_NAME_1, 266, 287, "n", 0.000000).
+arc(NO_NAME_1, 267, 288, "t", 0.000000).
+arc(NO_NAME_1, 268, 289, "t", 0.000000).
+arc(NO_NAME_1, 269, 290, "j", 0.000000).
+arc(NO_NAME_1, 270, 291, "0":")", 0.000000).
+arc(NO_NAME_1, 271, 292, "m", 0.000000).
+arc(NO_NAME_1, 272, 293, "e", 0.000000).
+arc(NO_NAME_1, 273, 294, "m", 0.000000).
+arc(NO_NAME_1, 274, 295, "t", 0.000000).
+arc(NO_NAME_1, 275, 296, "0":".", 0.000000).
+arc(NO_NAME_1, 276, 297, "i":"ì", 0.000000).
+arc(NO_NAME_1, 277, 298, "0":".", 0.000000).
+arc(NO_NAME_1, 278, 299, "s", 0.000000).
+arc(NO_NAME_1, 279, 300, "0":".", 0.000000).
+arc(NO_NAME_1, 280, 301, "t", 0.000000).
+arc(NO_NAME_1, 281, 302, "l", 0.000000).
+arc(NO_NAME_1, 282, 303, "t", 0.000000).
+arc(NO_NAME_1, 283, 304, "0":".", 0.000000).
+arc(NO_NAME_1, 284, 305, "0":")", 0.000000).
+arc(NO_NAME_1, 285, 306, "0":")", 0.000000).
+arc(NO_NAME_1, 286, 307, "0":")", 0.000000).
+arc(NO_NAME_1, 287, 308, "0":")", 0.000000).
+arc(NO_NAME_1, 288, 309, "u", 0.000000).
+arc(NO_NAME_1, 289, 310, "u", 0.000000).
+arc(NO_NAME_1, 290, 311, "a", 0.000000).
+arc(NO_NAME_1, 291, 312, "0":".", 0.000000).
+arc(NO_NAME_1, 292, 313, "ä", 0.000000).
+arc(NO_NAME_1, 293, 314, "0":")", 0.000000).
+arc(NO_NAME_1, 294, 315, "ä", 0.000000).
+arc(NO_NAME_1, 295, 316, "0":")", 0.000000).
+arc(NO_NAME_1, 296, 317, "m", 0.000000).
+arc(NO_NAME_1, 297, 318, "s", 0.000000).
+arc(NO_NAME_1, 298, 319, "k", 0.000000).
+arc(NO_NAME_1, 299, 320, "a", 0.000000).
+arc(NO_NAME_1, 300, 321, "t", 0.000000).
+arc(NO_NAME_1, 301, 322, "0":".", 0.000000).
+arc(NO_NAME_1, 302, 323, "a", 0.000000).
+arc(NO_NAME_1, 303, 324, "a", 0.000000).
+arc(NO_NAME_1, 304, 325, "0":"(", 0.000000).
+arc(NO_NAME_1, 306, 326, "0":".", 0.000000).
+arc(NO_NAME_1, 309, 327, "0":".", 0.000000).
+arc(NO_NAME_1, 310, 328, "0":")", 0.000000).
+arc(NO_NAME_1, 311, 329, "0":")", 0.000000).
+arc(NO_NAME_1, 312, 330, "0":"(", 0.000000).
+arc(NO_NAME_1, 313, 331, "l", 0.000000).
+arc(NO_NAME_1, 314, 332, "0":".", 0.000000).
+arc(NO_NAME_1, 315, 333, "l", 0.000000).
+arc(NO_NAME_1, 317, 334, "e", 0.000000).
+arc(NO_NAME_1, 318, 335, "0":".", 0.000000).
+arc(NO_NAME_1, 319, 336, "a", 0.000000).
+arc(NO_NAME_1, 320, 337, "0":")", 0.000000).
+arc(NO_NAME_1, 321, 338, "a", 0.000000).
+arc(NO_NAME_1, 322, 339, "t", 0.000000).
+arc(NO_NAME_1, 323, 340, "0":".", 0.000000).
+arc(NO_NAME_1, 324, 341, "0":".", 0.000000).
+arc(NO_NAME_1, 325, 342, "m", 0.000000).
+arc(NO_NAME_1, 326, 343, "j", 0.000000).
+arc(NO_NAME_1, 327, 344, "m", 0.000000).
+arc(NO_NAME_1, 328, 345, "0":".", 0.000000).
+arc(NO_NAME_1, 330, 346, "m", 0.000000).
+arc(NO_NAME_1, 331, 347, "0":".", 0.000000).
+arc(NO_NAME_1, 332, 348, "0":"(", 0.000000).
+arc(NO_NAME_1, 333, 349, "0":")", 0.000000).
+arc(NO_NAME_1, 334, 350, "0":")", 0.000000).
+arc(NO_NAME_1, 335, 351, "m", 0.000000).
+arc(NO_NAME_1, 336, 352, "0":")", 0.000000).
+arc(NO_NAME_1, 338, 353, "0":".", 0.000000).
+arc(NO_NAME_1, 339, 354, "e", 0.000000).
+arc(NO_NAME_1, 340, 355, "n", 0.000000).
+arc(NO_NAME_1, 341, 356, "n", 0.000000).
+arc(NO_NAME_1, 342, 357, "i":"ì", 0.000000).
+arc(NO_NAME_1, 343, 358, "a", 0.000000).
+arc(NO_NAME_1, 343, 359, "a":"à", 0.000000).
+arc(NO_NAME_1, 344, 360, "i", 0.000000).
+arc(NO_NAME_1, 345, 361, "0":"(", 0.000000).
+arc(NO_NAME_1, 346, 362, "a":"à", 0.000000).
+arc(NO_NAME_1, 347, 363, "l", 0.000000).
+arc(NO_NAME_1, 348, 364, "m", 0.000000).
+arc(NO_NAME_1, 349, 365, "0":".", 0.000000).
+arc(NO_NAME_1, 351, 366, "i", 0.000000).
+arc(NO_NAME_1, 353, 367, "r", 0.000000).
+arc(NO_NAME_1, 354, 368, "0":".", 0.000000).
+arc(NO_NAME_1, 355, 369, "i", 0.000000).
+arc(NO_NAME_1, 356, 370, "i", 0.000000).
+arc(NO_NAME_1, 357, 371, "0":".", 0.000000).
+arc(NO_NAME_1, 358, 372, "t", 0.000000).
+arc(NO_NAME_1, 359, 373, "t", 0.000000).
+arc(NO_NAME_1, 360, 374, "0":")", 0.000000).
+arc(NO_NAME_1, 361, 375, "m", 0.000000).
+arc(NO_NAME_1, 362, 376, "0":".", 0.000000).
+arc(NO_NAME_1, 363, 377, "i", 0.000000).
+arc(NO_NAME_1, 364, 378, "ä":"ä`", 0.000000).
+arc(NO_NAME_1, 365, 379, "0":"(", 0.000000).
+arc(NO_NAME_1, 366, 380, "0":")", 0.000000).
+arc(NO_NAME_1, 367, 381, "i", 0.000000).
+arc(NO_NAME_1, 368, 382, "l", 0.000000).
+arc(NO_NAME_1, 369, 383, "0":")", 0.000000).
+arc(NO_NAME_1, 370, 384, "0":")", 0.000000).
+arc(NO_NAME_1, 371, 385, "n", 0.000000).
+arc(NO_NAME_1, 374, 386, "0":".", 0.000000).
+arc(NO_NAME_1, 375, 387, "i":"ì", 0.000000).
+arc(NO_NAME_1, 376, 388, "n", 0.000000).
+arc(NO_NAME_1, 377, 389, "0":")", 0.000000).
+arc(NO_NAME_1, 378, 390, "t", 0.000000).
+arc(NO_NAME_1, 379, 391, "l", 0.000000).
+arc(NO_NAME_1, 381, 392, "0":")", 0.000000).
+arc(NO_NAME_1, 382, 393, "e", 0.000000).
+arc(NO_NAME_1, 385, 394, "e", 0.000000).
+arc(NO_NAME_1, 386, 395, "0":"(", 0.000000).
+arc(NO_NAME_1, 387, 396, "0":".", 0.000000).
+arc(NO_NAME_1, 388, 397, "i", 0.000000).
+arc(NO_NAME_1, 389, 398, "0":".", 0.000000).
+arc(NO_NAME_1, 390, 399, "0":".", 0.000000).
+arc(NO_NAME_1, 391, 400, "i":"ì", 0.000000).
+arc(NO_NAME_1, 392, 401, "0":".", 0.000000).
+arc(NO_NAME_1, 393, 402, "0":")", 0.000000).
+arc(NO_NAME_1, 394, 403, "n", 0.000000).
+arc(NO_NAME_1, 395, 404, "s", 0.000000).
+arc(NO_NAME_1, 396, 405, "n", 0.000000).
+arc(NO_NAME_1, 397, 406, "0":")", 0.000000).
+arc(NO_NAME_1, 398, 407, "0":"(", 0.000000).
+arc(NO_NAME_1, 399, 408, "t", 0.000000).
+arc(NO_NAME_1, 400, 409, "s", 0.000000).
+arc(NO_NAME_1, 401, 410, "0":"(", 0.000000).
+arc(NO_NAME_1, 402, 411, "0":".", 0.000000).
+arc(NO_NAME_1, 403, 412, "0":")", 0.000000).
+arc(NO_NAME_1, 404, 413, "e":"è", 0.000000).
+arc(NO_NAME_1, 405, 414, "e", 0.000000).
+arc(NO_NAME_1, 406, 415, "0":".", 0.000000).
+arc(NO_NAME_1, 407, 416, "s", 0.000000).
+arc(NO_NAME_1, 408, 417, "ö", 0.000000).
+arc(NO_NAME_1, 409, 418, "0":".", 0.000000).
+arc(NO_NAME_1, 410, 419, "a":"à", 0.000000).
+arc(NO_NAME_1, 411, 420, "0":"(", 0.000000).
+arc(NO_NAME_1, 413, 421, "s", 0.000000).
+arc(NO_NAME_1, 414, 422, "n", 0.000000).
+arc(NO_NAME_1, 415, 423, "k", 0.000000).
+arc(NO_NAME_1, 416, 424, "y":"y`", 0.000000).
+arc(NO_NAME_1, 417, 425, "0":")", 0.000000).
+arc(NO_NAME_1, 418, 426, "t", 0.000000).
+arc(NO_NAME_1, 419, 427, "n", 0.000000).
+arc(NO_NAME_1, 420, 428, "m", 0.000000).
+arc(NO_NAME_1, 421, 429, "0":".", 0.000000).
+arc(NO_NAME_1, 422, 430, "0":")", 0.000000).
+arc(NO_NAME_1, 423, 431, "i":"ì", 0.000000).
+arc(NO_NAME_1, 423, 432, "i", 0.000000).
+arc(NO_NAME_1, 424, 433, "y", 0.000000).
+arc(NO_NAME_1, 425, 434, "0":".", 0.000000).
+arc(NO_NAME_1, 426, 435, "ä", 0.000000).
+arc(NO_NAME_1, 427, 436, "0":".", 0.000000).
+arc(NO_NAME_1, 428, 437, "a":"à", 0.000000).
+arc(NO_NAME_1, 429, 438, "t", 0.000000).
+arc(NO_NAME_1, 431, 439, "n", 0.000000).
+arc(NO_NAME_1, 432, 440, "n", 0.000000).
+arc(NO_NAME_1, 433, 441, "0":".", 0.000000).
+arc(NO_NAME_1, 434, 442, "0":"(", 0.000000).
+arc(NO_NAME_1, 435, 443, "0":".", 0.000000).
+arc(NO_NAME_1, 436, 444, "s", 0.000000).
+arc(NO_NAME_1, 437, 445, "s", 0.000000).
+arc(NO_NAME_1, 438, 446, "a", 0.000000).
+arc(NO_NAME_1, 441, 447, "d", 0.000000).
+arc(NO_NAME_1, 442, 448, "m", 0.000000).
+arc(NO_NAME_1, 443, 449, "m", 0.000000).
+arc(NO_NAME_1, 444, 450, "a", 0.000000).
+arc(NO_NAME_1, 445, 451, "0":".", 0.000000).
+arc(NO_NAME_1, 446, 452, "0":")", 0.000000).
+arc(NO_NAME_1, 447, 453, "e", 0.000000).
+arc(NO_NAME_1, 448, 454, "y":"y`", 0.000000).
+arc(NO_NAME_1, 449, 455, "ä", 0.000000).
+arc(NO_NAME_1, 450, 456, "0":")", 0.000000).
+arc(NO_NAME_1, 451, 457, "t", 0.000000).
+arc(NO_NAME_1, 453, 458, "l", 0.000000).
+arc(NO_NAME_1, 454, 459, "y", 0.000000).
+arc(NO_NAME_1, 455, 460, "0":")", 0.000000).
+arc(NO_NAME_1, 457, 461, "a", 0.000000).
+arc(NO_NAME_1, 458, 462, "0":")", 0.000000).
+arc(NO_NAME_1, 459, 463, "0":".", 0.000000).
+arc(NO_NAME_1, 460, 464, "0":".", 0.000000).
+arc(NO_NAME_1, 461, 465, "0":")", 0.000000).
+arc(NO_NAME_1, 462, 466, "0":".", 0.000000).
+arc(NO_NAME_1, 463, 467, "d", 0.000000).
+arc(NO_NAME_1, 464, 468, "0":"(", 0.000000).
+arc(NO_NAME_1, 466, 469, "0":"(", 0.000000).
+arc(NO_NAME_1, 467, 470, "e", 0.000000).
+arc(NO_NAME_1, 468, 471, "t", 0.000000).
+arc(NO_NAME_1, 469, 472, "l", 0.000000).
+arc(NO_NAME_1, 470, 473, "s", 0.000000).
+arc(NO_NAME_1, 471, 474, "ö":"ö`", 0.000000).
+arc(NO_NAME_1, 472, 475, "ä":"ä`", 0.000000).
+arc(NO_NAME_1, 473, 476, "0":")", 0.000000).
+arc(NO_NAME_1, 474, 477, "n", 0.000000).
+arc(NO_NAME_1, 475, 478, "0":".", 0.000000).
+arc(NO_NAME_1, 476, 479, "0":".", 0.000000).
+arc(NO_NAME_1, 477, 480, "0":".", 0.000000).
+arc(NO_NAME_1, 478, 481, "n", 0.000000).
+arc(NO_NAME_1, 479, 482, "0":"(", 0.000000).
+arc(NO_NAME_1, 480, 483, "t", 0.000000).
+arc(NO_NAME_1, 481, 484, "i", 0.000000).
+arc(NO_NAME_1, 482, 485, "t", 0.000000).
+arc(NO_NAME_1, 483, 486, "ä", 0.000000).
+arc(NO_NAME_1, 484, 487, "0":")", 0.000000).
+arc(NO_NAME_1, 485, 488, "ä":"ä`", 0.000000).
+arc(NO_NAME_1, 486, 489, "0":")", 0.000000).
+arc(NO_NAME_1, 488, 490, "n", 0.000000).
+arc(NO_NAME_1, 490, 491, "0":".", 0.000000).
+arc(NO_NAME_1, 491, 492, "s", 0.000000).
+arc(NO_NAME_1, 492, 493, "ä", 0.000000).
+arc(NO_NAME_1, 493, 494, "0":")", 0.000000).
+final(NO_NAME_1, 109, 0.000000).
+final(NO_NAME_1, 160, 0.000000).
+final(NO_NAME_1, 203, 0.000000).
+final(NO_NAME_1, 204, 0.000000).
+final(NO_NAME_1, 254, 0.000000).
+final(NO_NAME_1, 305, 0.000000).
+final(NO_NAME_1, 307, 0.000000).
+final(NO_NAME_1, 308, 0.000000).
+final(NO_NAME_1, 316, 0.000000).
+final(NO_NAME_1, 329, 0.000000).
+final(NO_NAME_1, 337, 0.000000).
+final(NO_NAME_1, 350, 0.000000).
+final(NO_NAME_1, 352, 0.000000).
+final(NO_NAME_1, 372, 0.000000).
+final(NO_NAME_1, 373, 0.000000).
+final(NO_NAME_1, 380, 0.000000).
+final(NO_NAME_1, 383, 0.000000).
+final(NO_NAME_1, 384, 0.000000).
+final(NO_NAME_1, 412, 0.000000).
+final(NO_NAME_1, 430, 0.000000).
+final(NO_NAME_1, 439, 0.000000).
+final(NO_NAME_1, 440, 0.000000).
+final(NO_NAME_1, 452, 0.000000).
+final(NO_NAME_1, 456, 0.000000).
+final(NO_NAME_1, 465, 0.000000).
+final(NO_NAME_1, 487, 0.000000).
+final(NO_NAME_1, 489, 0.000000).
+final(NO_NAME_1, 494, 0.000000).
diff --git a/test/tools/fsmbook-tests/expected-results/Palindromes.prolog b/test/tools/fsmbook-tests/expected-results/Palindromes.prolog
new file mode 100644
index 0000000..8196c90
--- /dev/null
+++ b/test/tools/fsmbook-tests/expected-results/Palindromes.prolog
@@ -0,0 +1,23 @@
+network(NO_NAME_1).
+arc(NO_NAME_1, 0, 1, "r", 0.000000).
+arc(NO_NAME_1, 0, 2, "m", 0.000000).
+arc(NO_NAME_1, 0, 3, "d", 0.000000).
+arc(NO_NAME_1, 1, 4, "a", 0.000000).
+arc(NO_NAME_1, 2, 5, "a", 0.000000).
+arc(NO_NAME_1, 3, 6, "e", 0.000000).
+arc(NO_NAME_1, 4, 7, "c", 0.000000).
+arc(NO_NAME_1, 5, 8, "d", 0.000000).
+arc(NO_NAME_1, 6, 9, "l", 0.000000).
+arc(NO_NAME_1, 7, 10, "e", 0.000000).
+arc(NO_NAME_1, 8, 11, "a", 0.000000).
+arc(NO_NAME_1, 9, 12, "e", 0.000000).
+arc(NO_NAME_1, 10, 13, "c", 0.000000).
+arc(NO_NAME_1, 11, 19, "m", 0.000000).
+arc(NO_NAME_1, 12, 14, "v", 0.000000).
+arc(NO_NAME_1, 13, 15, "a", 0.000000).
+arc(NO_NAME_1, 14, 16, "e", 0.000000).
+arc(NO_NAME_1, 15, 19, "r", 0.000000).
+arc(NO_NAME_1, 16, 17, "l", 0.000000).
+arc(NO_NAME_1, 17, 18, "e", 0.000000).
+arc(NO_NAME_1, 18, 19, "d", 0.000000).
+final(NO_NAME_1, 19, 0.000000).
diff --git a/test/tools/fsmbook-tests/fst2fst.py b/test/tools/fsmbook-tests/fst2fst.py
new file mode 100644
index 0000000..8f0d38d
--- /dev/null
+++ b/test/tools/fsmbook-tests/fst2fst.py
@@ -0,0 +1,36 @@
+import sys
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+    raise RuntimeError('Usage: fst2fst.py [sfst|openfst|foma] [[PYTHONPATH]]')
+if len(sys.argv) == 3:
+    sys.path.insert(0, sys.argv[2])
+import hfst
+
+if (sys.argv[1] == 'sfst'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.SFST_TYPE)
+    else:
+        raise RuntimeError('Format sfst is not available.')
+elif (sys.argv[1] == 'openfst' or sys.argv[1] == "openfst-tropical"):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)
+    else:
+        raise RuntimeError('Format openfst is not available.')
+elif (sys.argv[1] == 'foma'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.FOMA_TYPE)
+    else:
+        raise RuntimeError('Format foma is not available.')
+else:
+    raise RuntimeError('Transducer format "' + sys.argv[1] + '" not recognized.')
+
+istr = hfst.HfstInputStream()
+ostr = hfst.HfstOutputStream()
+while(True):
+    try:
+        tr = istr.read()
+        tr.convert(hfst.get_default_fst_type())
+        ostr.write(tr)
+        ostr.flush()
+    except hfst.exceptions.EndOfStreamException as e:
+        break
+
diff --git a/test/tools/fsmbook-tests/fst2strings.py b/test/tools/fsmbook-tests/fst2strings.py
new file mode 100644
index 0000000..e3d5149
--- /dev/null
+++ b/test/tools/fsmbook-tests/fst2strings.py
@@ -0,0 +1,15 @@
+import sys
+if len(sys.argv) > 2:
+    raise RuntimeError('Usage: fst2strings.py [[PYTHONPATH]]')
+if len(sys.argv) == 2:
+    sys.path.insert(0, sys.argv[1])
+import hfst
+
+istr = hfst.HfstInputStream()
+while(True):
+    try:
+        tr = istr.read()
+        print((tr.extract_paths(output='text')).replace(hfst.EPSILON, ''))
+    except hfst.exceptions.EndOfStreamException as e:
+        break
+
diff --git a/test/tools/fsmbook-tests/fst2strings_space.py b/test/tools/fsmbook-tests/fst2strings_space.py
new file mode 100644
index 0000000..160b652
--- /dev/null
+++ b/test/tools/fsmbook-tests/fst2strings_space.py
@@ -0,0 +1,23 @@
+from __future__ import print_function
+
+import sys
+if len(sys.argv) > 2:
+    raise RuntimeError('Usage: fst2strings.py [[PYTHONPATH]]')
+if len(sys.argv) == 2:
+    sys.path.insert(0, sys.argv[1])
+import hfst
+
+istr = hfst.HfstInputStream()
+while(True):
+    try:
+        tr = istr.read()
+        paths = tr.extract_paths(output='raw')
+        for path in paths:
+            for tokenpair in path[1]:
+                if tokenpair[0] == tokenpair[1]:
+                    print(tokenpair[0], end=' ')
+                else:
+                    print(tokenpair[0]+':'+tokenpair[1], end=' ')
+    except hfst.exceptions.EndOfStreamException as e:
+        break
+
diff --git a/test/tools/fsmbook-tests/list_formats.py b/test/tools/fsmbook-tests/list_formats.py
new file mode 100644
index 0000000..6c86652
--- /dev/null
+++ b/test/tools/fsmbook-tests/list_formats.py
@@ -0,0 +1,21 @@
+import sys
+if len(sys.argv) > 2:
+    raise RuntimeError('Usage: list_formats.py [[PYTHONPATH]]')
+if len(sys.argv) == 2:
+    sys.path.insert(0, sys.argv[1])
+import hfst
+
+print('Backend                         Names recognized')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE)):
+    print('SFST                            sfst')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)):
+    print('OpenFst (tropical weights)      openfst-tropical, openfst, ofst, ofst-tropical')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.LOG_OPENFST_TYPE)):
+    print('OpenFst (logarithmic weights)   openfst-log, ofst-log')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE)):
+    print('foma                            foma')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.HFST_OL_TYPE)):
+    print('Optimized lookup (weighted)     optimized-lookup-unweighted, olu')
+if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.HFST_OLW_TYPE)):
+    print('Optimized lookup (unweighted)   optimized-lookup-weighted, olw, optimized-lookup, ol')
+
diff --git a/test/tools/fsmbook-tests/prolog2fst.py b/test/tools/fsmbook-tests/prolog2fst.py
new file mode 100644
index 0000000..da1c7dd
--- /dev/null
+++ b/test/tools/fsmbook-tests/prolog2fst.py
@@ -0,0 +1,43 @@
+import sys
+if len(sys.argv) < 2 or len(sys.argv) > 3:
+    raise RuntimeError('Usage: prolog2fst.py [sfst|openfst|foma] [[PYTHONPATH]]')
+if len(sys.argv) == 3:
+    sys.path.insert(0, sys.argv[2])
+import hfst
+
+if (sys.argv[1] == 'sfst'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.SFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.SFST_TYPE)
+    else:
+        raise RuntimeError('Format sfst is not available.')
+elif (sys.argv[1] == 'openfst' or sys.argv[1] == "openfst-tropical"):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.TROPICAL_OPENFST_TYPE)
+    else:
+        raise RuntimeError('Format openfst is not available.')
+elif (sys.argv[1] == 'foma'):
+    if (hfst.HfstTransducer.is_implementation_type_available(hfst.ImplementationType.FOMA_TYPE)):
+        hfst.set_default_fst_type(hfst.ImplementationType.FOMA_TYPE)
+    else:
+        raise RuntimeError('Format foma is not available.')
+else:
+    raise RuntimeError('Transducer format "' + sys.argv[1] + '" not recognized.')
+
+ostr = hfst.HfstOutputStream()
+
+# Works for python 3 only
+input_stream=None
+if sys.version_info[0] > 2:
+	import io
+	input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
+else:
+	raise RuntimeError('Cannot read utf-8 input from standard input with python version 2.')
+
+while(True):
+    try:
+        tr = hfst.read_prolog_transducer(input_stream)
+        ostr.write(tr)
+        ostr.flush()
+    except hfst.exceptions.EndOfStreamException as e:
+        break
+
diff --git a/test/tools/fsmbook-tests/python-scripts/BetterColaMachine.hfst.py b/test/tools/fsmbook-tests/python-scripts/BetterColaMachine.hfst.py
new file mode 100644
index 0000000..1e179e2
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/BetterColaMachine.hfst.py
@@ -0,0 +1,5 @@
+exec(compile(open('CompileOptions.py', "rb").read(), 'CompileOptions.py', 'exec'))
+
+tr = hfst.regex(' [ D -> N^2, Q -> N^5 ] ')
+tr.write_to_file('Result')
+
diff --git a/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese1.hfst.py b/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese1.hfst.py
new file mode 100644
index 0000000..1b5ea5b
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese1.hfst.py
@@ -0,0 +1,46 @@
+
+exec(compile(open('CompileOptions.py', "rb").read(), 'CompileOptions.py', 'exec'))
+
+tr = hfst.regex("[ a | e | i | o | u \
+                 | á | é | í | ó | ú \
+                 | â | ê |     ô     \
+                 | ã |         õ     \
+                 | à                 \
+                 |                 ü \
+                 ]")
+
+tr.write_to_file('Vowel')
+
+tr = hfst.regex('[ s -> z || @"Vowel" _ @"Vowel" ] \
+  .o. \
+  [ ç -> s ] \
+  .o. \
+       [ c h -> %$ ] \
+        .o.  \
+       [ c -> s || _ [ e | i | é | í | ê ] ] \
+        .o.  \
+  [ c -> k ] \
+   .o.  \
+  [ s s -> s ] \
+   .o.  \
+  [ n h -> N ] \
+   .o.  \
+  [ l h -> L ] \
+   .o.  \
+  [ h -> 0 ] \
+   .o.  \
+  [ r r -> R ] \
+   .o.  \
+  [ r -> R || .#. _ ] \
+   .o.  \
+  [ e -> i || _ (s) .#. , .#. p _ r ] \
+   .o.  \
+  [ o -> u || _ (s) .#. ] \
+   .o.  \
+  [ d -> J || _ [ i | ì ] ] \
+   .o.  \
+  [ t -> C || _ [ i | ì ] ] \
+   .o.  \
+  [ z -> s || _ .#. ]' )
+
+tr.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese2.hfst.py b/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese2.hfst.py
new file mode 100644
index 0000000..116af56
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/BrazilianPortuguese2.hfst.py
@@ -0,0 +1,45 @@
+exec(compile(open('CompileOptions.py', "rb").read(), 'CompileOptions.py', 'exec'))
+
+tr = hfst.regex("[ a | e | i | o | u \
+     | á | é | í | ó | ú  \
+     | â | ê |     ô      \
+     | ã |         õ      \
+     | à                  \
+     |                 ü  \
+     ]")
+
+tr.write_to_file('Vowel')
+
+tr = hfst.regex('[ s -> z || @"Vowel" _ @"Vowel" ] \
+ .o.  \
+  [ ç -> s ] \
+   .o.  \
+  [ c h -> %$ ] \
+   .o.  \
+  [ c -> s || _ [ e | i | é | í | ê ] ] \
+   .o.  \
+  [ c -> k ] \
+   .o.  \
+  [ s s -> s ] \
+   .o.  \
+  [ n h -> N ] \
+   .o.  \
+  [ l h -> L ] \
+   .o.  \
+  [ h -> 0 ] \
+   .o.  \
+  [ r r -> R ] \
+   .o.  \
+  [ r -> R || .#. _ ] \
+   .o.  \
+  [ e -> i || _ (s) .#. , .#. p _ r ] \
+   .o.  \
+  [ o -> u || _ (s) .#. ] \
+   .o.  \
+  [ d -> J || _ [ i | í ] ] \
+   .o.  \
+  [ t -> C || _ [ i | í ] ] \
+   .o.  \
+  [ z -> s || _ .#. ]')
+
+tr.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/DateParser.hfst.py b/test/tools/fsmbook-tests/python-scripts/DateParser.hfst.py
new file mode 100644
index 0000000..cb710f2
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/DateParser.hfst.py
@@ -0,0 +1,82 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+verbose_regex=False
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+        if verbose_regex:
+            print("defined transducer '" + expression + "':")
+            print(tr)
+
+# Numbers from one to nine.
+regex('OneToNine', '[1|2|3|4|5|6|7|8|9]')
+regex('ZeroToNine', '["0"|OneToNine]')
+regex('Even', '[{0} | 2 | 4 | 6 | 8]')
+regex('Odd', '[1 | 3 | 5 | 7 | 9]')
+regex('Number', '[Even | Odd]')
+
+
+# Days of the week.
+regex('Day', '[{Monday} | {Tuesday} | {Wednesday} | {Thursday} | {Friday} | {Saturday} | {Sunday}]')
+
+# A special month that usually has only 28 days.
+regex('Month29', '{February}')
+# Months that have 30 days.
+regex('Month30', '[{April} | {June} | {September} | {November}]')
+# Months that have 31 days.
+regex('Month31', '[{January} | {March} | {May} | {July} | {August} | {October} | {December}]')
+# All months.
+regex('Month', '[Month29 | Month30 | Month31]')
+
+
+# Numbers from 1 to 31
+regex('Date', '[OneToNine | [1 | 2] ZeroToNine | 3 [%0 | 1]]')
+
+# Numbers from 1 to 9999
+
+#regex('Year', '[OneToNine ZeroToNine^<4]')
+#hfst-repeat -t 3 ZeroToNine | hfst-concatenate -1 OneToNine > Year;
+regex('Year', '[OneToNine [ZeroToNine]^<4]')
+  
+# Day or [Month and Date] with optional Day and Year
+# define AllDates [Day | (Day {, }) Month { } Date ({, } Year)];
+regex('AllDates', '[Day | (Day {, }) Month { } Date ({, } Year)]')
+
+
+# Constraints on dates 30 and 31
+regex('MaxDays30', '~$[Month29 { 30}]')
+regex('MaxDays31', '~$[[Month29 | Month30] { 31}]')
+
+# Combining constraints on dates 30 and 31
+regex('MaxDays', '[MaxDays30 & MaxDays31]')
+
+
+
+
+# Divisible by 4
+# Of single digit numbers, 4 and 8 are divisible by 4.
+# In larger numbers divisible with 4, if the penultimate
+# is even, the last number is 0, 4, or 8. If the penultimate
+# is odd, the last number is 2 or 6.
+regex('Div4', '[4 | 8 | Number* [Even [%0 | 4 | 8] | Odd [2 | 6]]]')
+
+
+# Leap years are divisible by 4 but we subtract centuries
+# that are not divisible by 400. Note the double
+# subtraction. [[N+ - Div4] {00}] includes 1900 but not 2000.
+regex('LeapYear', '[Div4 - [[Number+ - Div4] {00}]]')
+
+# Note the [.#. | \N] at the end of the right context.
+# 2405 is not a leap year although the year 240 was (in principle).
+regex('LeapDates', '{February 29, } => _ LeapYear [.#. | \\Number ]')
+
+regex('ValidDates', '[AllDates & MaxDays & LeapDates]')
+
+Result = regex(None, '[ValidDates @-> "<DATE>" ... "</DATE>"]')
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EinsteinsPuzzle.hfst.py b/test/tools/fsmbook-tests/python-scripts/EinsteinsPuzzle.hfst.py
new file mode 100644
index 0000000..20dab4b
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EinsteinsPuzzle.hfst.py
@@ -0,0 +1,127 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+# matches all symbols
+pi = hfst.read_att_string("0 0 @_IDENTITY_SYMBOL_@ @_IDENTITY_SYMBOL_@\n\
+0")
+
+# matches all symbols except "|"
+pi_house = hfst.read_att_string("0 0 @_IDENTITY_SYMBOL_@ @_IDENTITY_SYMBOL_@\n\
+0 1 | |\n\
+0")
+
+# The possible values of a house color (spaces are added for better readability)
+Color = hfst.fst(["blue ", "green ", "red ", "white ", "yellow "])
+
+# The possible values of nationality
+Nationality = hfst.fst(["Dane ", "Englishman ", "German ", "Swede ", "Norwegian "])
+
+# The possible values of a drink
+Drink = hfst.fst(["bier ", "coffee ", "milk ", "tea ", "water "])
+
+# The possible values of cigarettes
+Cigarette = hfst.fst(["Blend ", "BlueMaster ", "Dunhill ", "PallMall ", "Prince "])
+
+# The possible values of animals
+Pet = hfst.fst(["birds ", "cats ", "dogs ", "fish ", "horses "])
+
+Color.write_to_file('Color.py.hfst')
+Nationality.write_to_file('Nationality.py.hfst')
+Drink.write_to_file('Drink.py.hfst')
+Cigarette.write_to_file('Cigarette.py.hfst')
+Pet.write_to_file('Pet.py.hfst')
+
+# Convert all strings into transducers
+vars={}
+for i in ("blue ", "green ", "red ", "white ", "yellow ",
+          "Dane ", "Englishman ", "German ", "Swede ", "Norwegian ",
+          "bier ", "coffee ", "milk ", "tea ", "water ",
+          "Blend ", "BlueMaster ", "Dunhill ", "PallMall ", "Prince ",
+          "birds ", "cats ", "dogs ", "fish ", "horses "):
+    tr = hfst.fst(i)
+    vars[i] = tr
+
+# Separator character (spaces are included for better readability)
+HouseSeparator = hfst.fst("| ")
+
+# House contains the consecutive values "ColorNationalityDrinkCigarettePet"
+House = hfst.concatenate((Color, Nationality, Drink, Cigarette, Pet))
+
+# Houses is "House| House| House| House| House"
+tmp = hfst.concatenate((House, HouseSeparator))
+tmp.repeat_n(4)
+Houses = hfst.concatenate((tmp, House))
+
+# 1. The Englishman lives in the red house.
+# Since color and nationality are adjacent, it is enough to accept all strings that contain "red Englishman"
+tmp = hfst.fst("red Englishman")
+C1 = hfst.concatenate((pi, tmp, pi)) # .* "red Englishman" .*
+
+# 2. The Swede keeps dogs.
+# Now we must match the string between Swede and dog inside the same house.
+tmp1 = hfst.fst('Swede')
+tmp2 = hfst.fst('dogs')
+C2 = hfst.concatenate((pi, tmp1, pi_house, tmp2, pi)) # .* "Swede" .* "dogs" .*
+
+# 3. The Dane drinks tea
+C3 = hfst.concatenate((pi, vars['Dane '], vars['tea '], pi))
+
+# 4. The green house is just to the left of the white one
+C4 = hfst.concatenate((pi, vars['green '], pi_house, HouseSeparator, vars['white '], pi))
+
+# 5. The owner of the green house drinks coffee
+C5 = hfst.concatenate((pi, vars['green '], pi_house, vars['coffee '], pi))
+
+# 6. The Pall Mall smoker keeps birds
+C6 = hfst.concatenate((pi, vars['PallMall '], vars['birds '], pi))
+
+# 7. The owner of the yellow house smokes Dunhills
+C7 = hfst.concatenate((pi, vars['yellow '], pi_house, vars['Dunhill '], pi))
+
+# 8. The man in the center house drinks milk
+C8 = hfst.concatenate((pi_house, HouseSeparator, pi_house, HouseSeparator, pi_house,
+                       vars['milk '], pi_house, HouseSeparator, pi_house, HouseSeparator, pi_house))
+
+# 9. The Norwegian lives in the first house
+C9 = hfst.concatenate((pi_house, vars['Norwegian '], pi))
+
+# 10. The Blend smoker has a neighbor who keeps cats
+C101 = hfst.concatenate((pi, vars['Blend '], Pet, HouseSeparator, pi_house, vars['cats '], pi))
+C102 = hfst.concatenate((pi, vars['cats '], pi_house, HouseSeparator, pi_house, vars['Blend '], pi))
+C10 = hfst.disjunct((C101, C102))
+C10.minimize()
+
+# 11. The man who keeps horses lives next to the Dunhill smoker
+C111 = hfst.concatenate((pi, vars['horses '], HouseSeparator, pi_house, vars['Dunhill '], pi))
+C112 = hfst.concatenate((pi, vars['Dunhill '], pi_house, HouseSeparator, pi_house, vars['horses '], pi))
+C11 = hfst.disjunct((C111, C112))
+C11.minimize()
+
+# 12. The man who smokes Blue Masters drinks bier.
+C12 = hfst.concatenate((pi, vars['bier '], vars['BlueMaster '], pi))
+
+# 13. The German smokes Prince
+C13 = hfst.concatenate((pi, vars['German '], Drink, vars['Prince '], pi))
+
+# 14. The Norwegian lives next to the blue house
+C141 = hfst.concatenate((pi, vars['Norwegian '], pi_house, HouseSeparator, vars['blue '], pi))
+C142 = hfst.concatenate((pi, vars['blue '], pi_house, HouseSeparator, Color, vars['Norwegian '], pi))
+C14 = hfst.disjunct((C141, C142))
+C14.minimize()
+
+# 15. The Blend smoker has a neighbor who drinks water
+C151 = hfst.concatenate((pi, vars['Blend '], Pet, HouseSeparator, pi_house, vars['water '], pi))
+C152 = hfst.concatenate((pi, vars['water '], pi_house, HouseSeparator, pi_house, vars['Blend '], pi))
+C15 = hfst.disjunct((C151, C152))
+C15.minimize()
+
+
+
+# Let's minimize the constraint transducers to carry out conjunction more efficiently:
+Result = Houses
+for i in (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15):
+    i.minimize()
+    # Let's conjunct Houses with the constraints one by one:
+    Result.conjunct(i)
+    Result.minimize()
+
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EnglishNumerals.hfst.py b/test/tools/fsmbook-tests/python-scripts/EnglishNumerals.hfst.py
new file mode 100644
index 0000000..4e5753e
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EnglishNumerals.hfst.py
@@ -0,0 +1,57 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+
+# From "one" to "nine":
+OneToNine = hfst.fst(["one","two","three","four","five","six","seven","eight","nine"])
+#OneToNine.write_to_file('OneToNine.hfst')
+
+# It is convenient to define a set of prefixes that can be followed either by "teen" or by "ty":
+TeenTen = hfst.fst(["thir","fif","six","seven","eigh","nine"])
+#TeenTen.write_to_file('TeenTen.hfst')
+              
+# From "ten" to "nineteen":
+
+TenElevenTwelve = hfst.fst(["ten","eleven","twelve"])
+Teen = hfst.fst("teen")
+Four = hfst.fst("four")
+
+Teens = hfst.HfstTransducer(Four)
+Teens.disjunct(TeenTen)
+Teens.concatenate(Teen)
+Teens.disjunct(TenElevenTwelve)
+
+# echo "four" | $2/$TOOLDIR/hfst-strings2fst -f $1 | $2/$TOOLDIR/hfst-disjunct TeenTen.hfst | $2/$TOOLDIR/hfst-concatenate -2 Teen.hfst | $2/$TOOLDIR/hfst-disjunct TenElevenTwelve.hfst > Teens.hfst;
+
+# Let's define a set of prefixes that can be followed by "ty".
+
+TenStem = hfst.fst(["twen","for"])
+TenStem.disjunct(TeenTen)
+
+#echo "twen
+#for" | $2/$TOOLDIR/hfst-strings2fst -j -f $1 | $2/$TOOLDIR/hfst-disjunct TeenTen.hfst > TenStem.hfst;
+
+# TenStem is followed either by "ty" or by ty-" and a number from OneToNine.
+
+TMP = hfst.HfstTransducer(TenStem)
+Ty = hfst.fst("ty")
+TMP.concatenate(Ty)
+Epsilon = hfst.epsilon_fst()
+Hyphen = hfst.fst("-")
+Hyphen.concatenate(OneToNine)
+Hyphen.disjunct(Epsilon)
+TMP.concatenate(Hyphen)
+Tens = TMP
+
+OneToNine.disjunct(Teens)
+OneToNinetyNine = OneToNine
+OneToNinetyNine.disjunct(Tens)
+
+OneToNinetyNine.write_to_file('Result')
+
+#echo "ty" | $2/$TOOLDIR/hfst-strings2fst -f $1 | $2/$TOOLDIR/hfst-concatenate -1 TenStem.hfst > TMP.hfst;
+#echo "" | $2/$TOOLDIR/hfst-strings2fst -f $1 > Epsilon.hfst;
+#echo "-" | $2/$TOOLDIR/hfst-strings2fst -f $1 | $2/$TOOLDIR/hfst-concatenate -2 OneToNine.hfst | $2/$TOOLDIR/hfst-disjunct Epsilon.hfst | $2/$TOOLDIR/hfst-concatenate -1 TMP.hfst > Tens.hfst;
+
+#$2/$TOOLDIR/hfst-disjunct OneToNine.hfst Teens.hfst | $2/$TOOLDIR/hfst-disjunct -2 Tens.hfst > OneToNinetyNine.hfst;
+
+
diff --git a/test/tools/fsmbook-tests/python-scripts/EsperantoAdjectives.hfst.py b/test/tools/fsmbook-tests/python-scripts/EsperantoAdjectives.hfst.py
new file mode 100644
index 0000000..8673587
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EsperantoAdjectives.hfst.py
@@ -0,0 +1,15 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+AdjPrefix = hfst.regex('[( [m a l] | [n e] )]')
+Adjectives = hfst.fst(["bon","long","jun","alt","grav"])
+Adj = hfst.regex('[[e g] | [e t]]*')
+AdjEnd = hfst.regex('[a]')
+Number = hfst.regex('[(j)]')
+Case = hfst.regex('[(n)]')
+Result = hfst.regex('[0]')
+
+for tr in [AdjPrefix, Adjectives, Adj, AdjEnd, Number, Case]:
+    Result.concatenate(tr)
+
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EsperantoNouns.hfst.py b/test/tools/fsmbook-tests/python-scripts/EsperantoNouns.hfst.py
new file mode 100644
index 0000000..6eb9e90
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EsperantoNouns.hfst.py
@@ -0,0 +1,17 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+Nouns = hfst.fst(["bird","hund","kat","elefant"])
+
+Nmf = hfst.regex('[ [i n] | [e t] | [e g] ]*')
+
+Nend = hfst.regex('[o]')
+
+Number = hfst.regex('[(j)]')
+
+Case = hfst.regex('[(n)]')
+
+Result = hfst.regex('[0]')
+
+tr = hfst.concatenate([Result, Nouns, Nmf, Nend, Number, Case])
+tr.minimize()
+tr.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAdjectivesAndVerbs.hfst.py b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAdjectivesAndVerbs.hfst.py
new file mode 100644
index 0000000..5a079c9
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAdjectivesAndVerbs.hfst.py
@@ -0,0 +1,53 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+NounPrefix = hfst.regex('([MF%+:g 0:e])')
+
+NounRoots = hfst.fst(["bird","hund","kat","elefant"]) 
+
+AdjRoots = hfst.fst(["bon","long","jun","alt","grav"]) 
+
+VerbRoots = hfst.fst(["don","est","pens","dir","fal"]) 
+
+VerbPrefixes = hfst.regex('([Op%+:m 0:a 0:l] | [Neg%+:n 0:e])')
+
+Verb = hfst.regex('[%+Verb:0]')
+
+Aspect = hfst.regex('([%+Cont:a 0:d])')
+
+Vend = hfst.regex('[%+Inf:i] | [%+Pres:a 0:s] | [%+Past:i 0:s] | [%+Fut:o 0:s] | \
+                   [%+Cond:u 0:s] | [%+Subj:u]')
+
+Nmf = hfst.regex('%+Noun:0')
+
+Nend = hfst.regex('%+NSuff:o')
+Nend.write_to_file('Nend')
+
+Adjend = hfst.regex('%+ASuff:a')
+Adjend.write_to_file('Adjend')
+
+AugDimFem  = hfst.regex('[[%+Fem:i 0:n] | [%+Dim:e 0:t] | [%+Aug:e 0:g]]* [@"Nend" | @"Adjend"]')
+
+AdjPrefixes = hfst.regex('([Op%+:m 0:a 0:l] | [Neg%+:n 0:e])')
+
+AugDimNize = hfst.regex('[[%+Aug:e 0:g] | [%+Dim:e 0:t]]* [[[%+Nize:e 0:c] @"Nend"]|[@"Adjend"]]')
+
+Adj = hfst.regex('%+Adj:0')
+
+Number = hfst.regex('%+Pl:j | %+Sg:0')
+
+Case = hfst.regex('(%+Acc:n)')
+
+
+NounStem = hfst.concatenate([NounPrefix, NounRoots, Nmf, AugDimFem])
+
+AdjectiveStem = hfst.concatenate([AdjPrefixes, AdjRoots, Adj, AugDimNize])
+
+NounAdjStems = hfst.disjunct([NounStem, AdjectiveStem])
+
+NounAdjs = hfst.concatenate([NounAdjStems, Number, Case])
+
+Verbs = hfst.concatenate([VerbPrefixes, VerbRoots, Verb, Aspect, Vend])
+
+Result = hfst.disjunct([NounAdjs, Verbs])
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectives.hfst.py b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectives.hfst.py
new file mode 100644
index 0000000..71210f8
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectives.hfst.py
@@ -0,0 +1,33 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+NounRoots = hfst.fst(["bird","hund","kat","elefant"])
+
+AdjRoots = hfst.fst(["bon","long","jun","alt","grav"])
+
+NounPrefix = hfst.regex('[(g e)]')
+
+AdjPrefixes = hfst.regex('[ ([m a l] | [n e]) ]')
+
+Nend = hfst.regex('[o]')
+Nend.write_to_file('Nend')
+
+Adjend = hfst.regex('[a]')
+Adjend.write_to_file('Adjend')
+
+Number = hfst.regex('[(j)]')
+
+Case = hfst.regex('[(n)]')
+
+Nmf = hfst.regex('[ ([i n] | [e t] | [e g])* [@"Nend" | @"Adjend"] ]')
+
+Adj = hfst.regex('([e g] | [e t])* [@"Adjend" | [e c @"Nend"]]')
+
+NounStem = hfst.concatenate([NounPrefix, NounRoots, Nmf])
+
+AdjectiveStem = hfst.concatenate([AdjPrefixes, AdjRoots, Adj])
+
+Stems = hfst.disjunct([NounStem, AdjectiveStem])
+
+Result = hfst.concatenate([Stems, Number, Case])
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectivesWithTags.hfst.py b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectivesWithTags.hfst.py
new file mode 100644
index 0000000..16fbd5a
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/EsperantoNounsAndAdjectivesWithTags.hfst.py
@@ -0,0 +1,38 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+NounPrefix = hfst.regex('([MF%+:g 0:e])')
+
+NounRoots = hfst.fst(["bird","hund","kat","elefant"])
+
+AdjRoots = hfst.fst(["bon","long","jun","alt","grav"])
+
+Nmf = hfst.regex('%+Noun:0')
+
+Nend = hfst.regex('%+NSuff:o')
+Nend.write_to_file('Nend')
+
+Adjend = hfst.regex('%+ASuff:a')
+Adjend.write_to_file('Adjend')
+
+AugDimFem  = hfst.regex('[[%+Fem:i 0:n] | [%+Dim:e 0:t] | [%+Aug:e 0:g]]* [@"Nend" | @"Adjend"]')
+
+AdjPrefixes = hfst.regex('([Op%+:m 0:a 0:l] | [Neg%+:n 0:e])')
+
+AugDimNize = hfst.regex('[[%+Aug:e 0:g] | [%+Dim:e 0:t]]* [[[%+Nize:e 0:c] @"Nend"]|[@"Adjend"]]')
+
+Adj = hfst.regex('%+Adj:0')
+
+Number = hfst.regex('%+Pl:j | %+Sg:0')
+
+Case = hfst.regex('(%+Acc:n)')
+	
+
+NounStem = hfst.concatenate([NounPrefix, NounRoots, Nmf, AugDimFem])
+
+AdjectiveStem = hfst.concatenate([AdjPrefixes, AdjRoots, Adj, AugDimNize])
+
+Stems = hfst.disjunct([NounStem, AdjectiveStem])
+
+Result = hfst.concatenate([Stems, Number, Case])
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/FinnishNumerals.hfst.py b/test/tools/fsmbook-tests/python-scripts/FinnishNumerals.hfst.py
new file mode 100644
index 0000000..7ba06e3
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/FinnishNumerals.hfst.py
@@ -0,0 +1,47 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+
+# First, we create a transducer that maps numbers 2 ... 9 to the corresponding numerals:
+two_to_nine = hfst.fst({'2':'kaksi',
+                        '3':'kolme',
+                        '4':'neljä',
+                        '5':'viisi',
+                        '6':'kuusi',
+                        '7':'seitsemän',
+                        '8':'kahdeksan',
+                        '9':'yhdeksän'})
+
+# and 1 ... 9:
+tmp = hfst.fst({'1':'yksi'})
+one_to_nine = hfst.disjunct((tmp, two_to_nine))
+
+# 10 is handled as a separate case:
+ten = hfst.fst({'10':'kymmenen'})
+
+# From 11 to 19, i.e.  [ 1:0 1to9 0:toista ]:
+one_to_eps = hfst.fst({'1':''})
+eps_to_toista = hfst.fst({'':'toista'})
+eleven_to_nineteen = hfst.concatenate((one_to_eps, one_to_nine, eps_to_toista))
+
+# From 20 to 99, i.e.  [ 2to9 0:kymmentä ( "0":0 | 1to9 ) ]:
+eps_to_kymmenta = hfst.fst({'':'kymmentä'})
+zero_to_eps = hfst.fst({'0':''})
+TMP = hfst.concatenate((two_to_nine, eps_to_kymmenta))
+tmp = hfst.disjunct((one_to_nine, zero_to_eps))
+twenty_to_ninetynine = hfst.concatenate((TMP, tmp))
+
+# Finally, from 1 to 99:
+FinnishNumerals = hfst.disjunct((one_to_nine, ten, eleven_to_nineteen, twenty_to_ninetynine))
+FinnishNumerals.minimize()
+
+# To get transducers that map Finnish to English numerals and vice versa, we use
+# composition and inversion.
+# NOTE: we assume that the file NumbersToNumerals is already created
+tr = hfst.HfstTransducer.read_from_file('tmpdir/NumbersToNumerals')
+tr.convert(hfst.get_default_fst_type())
+FinnishNumerals.invert()
+FinnishNumerals.compose(tr)
+FinnishNumerals.minimize()
+FinnishNumerals.invert()
+FinnishNumerals.minimize()
+FinnishNumerals.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/FinnishOTProsody.hfst.py b/test/tools/fsmbook-tests/python-scripts/FinnishOTProsody.hfst.py
new file mode 100644
index 0000000..e2aedd8
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/FinnishOTProsody.hfst.py
@@ -0,0 +1,229 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+
+# Data
+regex('FinnWords', "{kalastelet} | {kalasteleminen} | {ilmoittautuminen} | \
+                 {järjestelmättömyydestänsä} | {kalastelemme} | \
+                 {ilmoittautumisesta} | {järjestelmällisyydelläni} | \
+                 {järjestelmällistämätöntä} | {voimisteluttelemasta} | \
+                 {opiskelija} | {opettamassa} | {kalastelet} | \
+                 {strukturalismi} | {onnittelemanikin} | {mäki} | \
+                 {perijä} | {repeämä} | {ergonomia} | {puhelimellani} | \
+                 {matematiikka} | {puhelimistani} | {rakastajattariansa} | \
+                 {kuningas} | {kainostelijat} | {ravintolat} | \
+                 {merkonomin} ;")
+
+# Basic definitions
+
+regex('HighV', '[u | y | i]')                          # High vowel
+regex('MidV', '[e | o | ö]')                          # Mid vowel
+regex('LowV', '[a | ä]')                             # Low vowel
+regex('USV', '[HighV | MidV | LowV]')                  # Unstressed Vowel
+
+regex('C', "[b | c | d | f | g | h | j | k | l | m | n | p | q | r | s | t | v | w | x | z]")  # Consonant
+
+regex('MSV', '[á | é | í | ó | ú | ý | ä´ | ö´ ]')
+regex('SSV', '[à | è | ì | ò | ù | y` | ä` | ö`]')
+regex('SV', '[MSV | SSV]')                              # Stressed vowel
+regex('V', '[USV | SV] ')                               # Vowel
+
+regex('P', '[V | C]')                                   # Phone
+regex('B', '[[\P+] | .#. ]')                             # Boundary
+
+regex('E', '.#. | "."')                                 # Edge
+regex('SB', '[~$"." "." ~$"."]')                        # At most one syllable boundary
+
+regex('Light', '[C* V]')                                # Light syllable
+regex('Heavy', '[Light P+]')                            # Heavy syllable
+
+regex('S', '[Heavy | Light]')                           # Syllable
+regex('SS', '[S & $SV]')                                # Stressed syllable
+
+regex('US', '[S & ~$SV]')                               # Unstressed syllable
+regex('MSS', '[S & $MSV] ')                             # Syllable with main stress
+regex('BF', '[S "." S]')                                # Binary foot
+
+
+# Gen
+#echo "-- GEN ---"
+
+# A diphthong is a combination of two unlike vowels that together form
+# the nucleus of a syllable. In general, Finnish diphthongs end in a high vowel.
+# However, there are three exceptional high-mid diphthongs: ie, uo, and yö
+# that historically come from long ee, oo, and öö, respectively.
+# All other adjacent vowels must be separated by a syllable boundary.
+
+regex('MarkNonDiphthongs', ' [. .] -> "." || [HighV | MidV] _ LowV , i _ [MidV - e] , u _ [MidV - o] , y _ [MidV - ö] ;')
+
+# The general syllabification rule has exceptions. In particular, loan
+# words such as ate.isti 'atheist' must be partially syllabified in the
+# lexicon.
+
+
+regex('Syllabify', 'C* V+ C* @-> ... "." || _ C V')
+
+
+# Optionally adds primary or secondary stress to the first vowel
+# of each syllable.
+
+regex('Stress', 'a (->) á|à , e (->) é|è , i (->) í|ì , o (->) ó|ò , u (->) ú|ù , y (->) ý|y` , ä (->) ä´|ä` , ö (->) ö´|ö` || E C* _ ')
+              
+
+# Scan the word, optionally dividing it to any combination of
+# unary, binary, and ternary feet. Each foot must contain at least
+# one stressed syllable.
+
+
+regex('Scan', '[[S ("." S ("." S)) & $SS] (->) "(" ... ")" || E _ E]')
+
+# In keeping with the idea of "richness of the base", the Gen
+# function produces a great number of output candidates for
+# even short words. Long words have millions of possible outputs.
+
+regex('Gen', '[MarkNonDiphthongs .o. Syllabify .o. Stress .o. Scan]')
+
+# OT constraints
+
+#echo "--- OT constraints --- "
+
+# We use asterisks to mark constraint violations. Ordinary constraints
+# such as Lapse assign single asterisks as the violation marks and the
+# candidate with the fewest number is selected. Gradient constraints
+# such as AllFeetFirst mark violations with sequences of asterisks.
+# The number increases with distance from the word edge.
+
+# Every instance of * in an output candidate is a violation.
+
+regex('Viol', '${*}')
+
+
+
+# We prune candidates with "lenient composition" that eliminates
+# candidates that violate the constraint provided that at least
+# one output candidate survives.
+
+regex('Viol0', '~Viol')         # No violations
+regex('Viol1', '~[Viol^2]')     # At most one violation
+regex('Viol2', '~[Viol^3]')     # At most two violations
+regex('Viol3', '~[Viol^4]')     # etc.
+regex('Viol4', '~[Viol^5]')
+regex('Viol5', '~[Viol^6]')
+regex('Viol6', '~[Viol^7]')
+regex('Viol7', '~[Viol^8]')
+regex('Viol8', '~[Viol^9]')
+regex('Viol9', '~[Viol^10]')
+regex('Viol10', '~[Viol^11]')
+regex('Viol11', '~[Viol^12]')
+regex('Viol12', '~[Viol^13]')
+regex('Viol13', '~[Viol^14]')
+regex('Viol14', '~[Viol^15]')
+regex('Viol15', '~[Viol^16]')
+
+
+
+
+# This eliminates the violation marks after the candidate set has
+# been pruned by a constraint.
+
+regex('Pardon', '{*} -> 0')
+
+
+
+
+# Constraints
+
+#echo "CONSTRAINTS---"
+
+# In this section we define nine constraints for Finnish prosody,
+# listed in the order of their ranking: MainStress, Clash, AlignLeft,
+# FootBin, Lapse, NonFinal, StressToWeight, Parse, and AllFeetFirst.
+# For the one inviolable constraint, we assign no violation marks.
+# Clash, Align-Left and Foot-Bin are always satisfiable in Finnish
+# but we assign violation marks as not to depend on that knowledge.
+
+# Main Stress: The primary stress in Finnish is on the first
+#              syllable. This is an inviolable constraint.
+
+regex('MainStress', '[B MSS ~$MSS]')
+
+
+# Clash: No stress on adjacent syllables.
+# define Clash SS -> ... {*} || SS B _ ;
+regex('Clash', 'SS -> ... {*} || SS B _ ')
+
+
+
+# Align-Left: The stressed syllable is initial in the foot.
+
+regex('AlignLeft', 'SV -> ... {*} || .#. ~[?* "(" C*] _ ')
+
+
+# Foot-Bin: Feet are minimally bimoraic and maximally bisyllabic.
+# define FootBin ["(" Light ")" | "(" S ["." S]^>1] -> ... {*} ;
+regex('FootBin', '["(" Light ")" | "(" S ["." S]^>1] -> ... {*} ')
+
+
+# Lapse: Every unstressed syllable must be adjacent to a stressed
+# syllable.
+# define Lapse US -> ... {*} || [B US B] _ [B US B];
+regex('Lapse', 'US -> ... {*} || [B US B] _ [B US B]')
+
+
+# Non-Final: The final syllable is not stressed.
+
+regex('NonFinal', 'SS -> ... {*} || _ ~$S .#.')
+
+
+# Stress-To-Weight: Stressed syllables are heavy.
+
+regex('StressToWeight', '[SS & Light] -> ... {*} || _ ")"| E')
+
+
+# License-σ: Syllables are parsed into feet.
+
+regex('Parse', 'S -> ... {*} || E _ E')
+
+
+# All-Ft-Left: Every foot starts at the beginning of a
+#              prosodic word.
+
+regex('AllFeetFirst', '[ "(" -> ... {*} || .#. SB _ .o. "(" -> ... {*}^2 || .#. SB^2 _ .o. "(" -> ... {*}^3 || .#. SB^3 _ .o. "(" -> ... {*}^4 || .#. SB^4 _ .o. "(" -> ... {*}^5 || .#. SB^5 _ .o. "(" -> ... {*}^6 || .#. SB^6 _ .o. "(" -> ... {*}^7 || .#. SB^7 _ .o. "(" -> ... {*}^8 || .#. SB^8 _ ]')
+#echo '"(" -> ... {*} || .#. SB _ ' | $2/hfst-regexp2fst -f $1 > a0
+#echo '"(" -> ... {*}^2 || .#. SB^2 _ '  | $2/hfst-regexp2fst -f $1 > a1
+#echo '"(" -> ... {*}^3 || .#. SB^3 _ '  | $2/hfst-regexp2fst -f $1 > a2
+#echo '"(" -> ... {*}^4 || .#. SB^4 _ '  | $2/hfst-regexp2fst -f $1 > a3
+#echo '"(" -> ... {*}^5 || .#. SB^5 _ '  | $2/hfst-regexp2fst -f $1 > a4
+#echo '"(" -> ... {*}^6 || .#. SB^6 _ '  | $2/hfst-regexp2fst -f $1 > a5
+#echo '"(" -> ... {*}^7 || .#. SB^7 _ '  | $2/hfst-regexp2fst -f $1 > a6
+#echo '"(" -> ... {*}^8 || .#. SB^8 _ ' | $2/hfst-regexp2fst -f $1 > a7
+
+
+# Evaluation
+# Computing the prosody for FinnWords
+
+# Some constraints can always be satisfied; some constraints are
+# violated many times. The limits have been chosen to produce
+# a unique winner in all the 25 test cases in FinnWords.
+
+Result = regex(None, '[FinnWords .o. Gen .o. MainStress .o. Clash .O. Viol0 .o. Pardon .o. AlignLeft .O. Viol0 .o. FootBin .O. Viol0 .o. Pardon .o. Lapse .O. Viol3 .O. Viol2 .O. Viol1 .O. Viol0 .o. Pardon .o. NonFinal .O. Viol0 .o. Pardon .o. StressToWeight .O. Viol3 .O. Viol2 .O. Viol1 .O. Viol0 .o. Pardon .o. Parse .O. Viol3 .O. Viol2 .O. Viol1 .O. Viol0 .o. Pardon .o. AllFeetFirst .O. Viol15 .O. Viol14 .O. Viol13 Viol12 .O. Viol11 .O. Viol10 .O. Viol9 .O. Viol8 .O. Viol7 .O. Viol6  .O [...]
+Result.minimize()
+Result.write_to_file('Result')
+
+
+#echo '[ MainStress .o. Clash .O. Viol0 .o. Pardon .o. AlignLeft .O. Viol0 ]' | $2/hfst-regexp2fst -f $1 > FinnishOTProsody.hfst.hfst
+
+
+
+
+
+
+#echo '[FinnWords .o. Gen .o. MainStress .o. Clash .O. Viol0 .o. Pardon .o. AlignLeft .O. Viol0 .o. FootBin .O. Viol0 .o. Pardon .o. Lapse .O. Viol3 .O. Viol2 .O. Viol1 .O. Viol0 .o. Pardon .o. NonFinal .O. Viol0 .o. Pardon .o. StressToWeight .O. Viol3 .O. Viol2 .O. Viol1 .O. Viol0 .o. Pardon .o. Parse .O. Viol3 .O. Viol2 .O. Viol1 ]' | $2/hfst-regexp2fst -f $1 > Result
+
diff --git a/test/tools/fsmbook-tests/python-scripts/FinnishProsody.hfst.py b/test/tools/fsmbook-tests/python-scripts/FinnishProsody.hfst.py
new file mode 100644
index 0000000..b101b52
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/FinnishProsody.hfst.py
@@ -0,0 +1,126 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+verbose_regex=False
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+        if verbose_regex:
+            print("defined transducer '" + expression + "':")
+            print(tr)
+
+# The data
+FinnWords = hfst.fst(("kalastelet",
+                      "kalasteleminen",
+                      "ilmoittautuminen",
+                      "järjestelemättömyydestänsä",
+                      "kalastelemme",
+                      "ilmoittautumisesta",
+                      "järjestelmällisyydelläni",
+                      "järjestelmällistämätöntä",
+                      "voimisteluttelemasta",
+                      "opiskelija",
+                      "opettamassa",
+                      "kalastelet",
+                      "strukturalismi",
+                      "onnittelemanikin",
+                      "mäki",
+                      "perijä",
+                      "repeämä",
+                      "ergonomia",
+                      "puhelimellani",
+                      "matematiikka",
+                      "puhelimistani",
+                      "rakastajattariansa",
+                      "kuningas",
+                      "kainostelijat",
+                      "ravintolat",
+                      "merkonomin"))
+
+# Some definitions:
+
+regex('HighV', '[u | y | i]')
+regex('MidV', '[e | o | ö]')
+regex('LowV', '[a | ä]')
+regex('USV', '[ HighV | MidV | LowV ]')
+
+regex('C', '[ b | c | d | f | g | h | j | k | l | m | n | p | q | r | s | t | v | w | x | z ]')
+
+regex('MSV', '[á | é | í | ó | ú | ý | ä´ | ö´ ]')
+regex('SSV', '[à | è | ì | ò | ù | y` | ä` | ö` ]')
+regex('SV', '[ MSV | SSV ]')
+regex('V', '[ USV | SV ]')
+
+regex('P', '[ V | C ]')
+
+regex('B', '[[\P+] | .#.]')
+regex('E', '[ .#. | "."]')
+regex('SB', '[~$"." "." ~$"."]')
+
+regex('Light', '[ C* V ]')
+regex('Heavy', '[ Light P+ ]')
+
+regex('S', '[ Heavy | Light ]')
+regex('SS', '[ S & $SV ]')
+regex('US', '[ S & ~SV ]')
+regex('MSS', '[ S & $MSV ]')
+
+regex('BF', '[ S "." S ]')
+
+# Rules for prosody:
+
+MarkNonDiphtongs = regex(None,
+                         '[ [. .] -> "." || [ HighV | MidV ] _ LowV,\
+                         i _ [MidV - e],\
+                         u _ [MidV - o],\
+                         y _ [MidV - ö] ]')
+
+# The general syllabification rule has exceptions. In particular, loan
+# words such as ate.isti 'atheist' must be partially syllabified in the
+# lexicon.
+
+Syllabify = regex(None, ' C*  V+ C* @-> ... "." || _ C V ')
+
+TernaryFeet = regex(None,
+                    ' BF "." Light @-> "(" ... ")" \
+                    // [{).} | .#.] [BF "."]*  _ \
+                    ["." Heavy "." S ] | .#. ')
+
+# Scan all the unfooted material into binary feet.
+                     
+BinaryFeet = regex(None, ' BF @-> "(" ... ")" || .#.|"." _ .#.|"." ')
+
+# Assign the primary stress to the first vowel of the first syllable.
+
+MainStress = regex(None,
+                   ' a -> á, e -> é, i -> í, o -> ó,\
+                   u -> ú, y -> ý, ä -> "ä´", ö -> "ö´" || .#. "(" C* _')
+
+# Assign secondary stress to all initial vowels of non-initial syllables.
+
+SecondaryStress = regex(None,
+                        ' a -> à, e -> è, i -> ì, o -> ò,\
+                        u -> ù, y -> "y`", ä -> "ä`", ö -> "ö`"\
+                        || "(" C* _ ')
+
+# Assign an optional secondary stress to an unfooted final syllable
+# if it is heavy.
+
+OptFinalStress = regex(None,
+                       'a (->) à, e (->) è, i (->) ì,\
+                       o (->) ò, u (->) ù, y (->) "y`",\
+                       ä (->) "ä`", ö (->) "ö`" || "." C* _ P .#. ')
+
+# Calculate the composition of rules from =MarkNonDiphtongs= to =OptFinalStress=
+# and compose the lexicon with the composition of rules.
+
+Rules = hfst.compose((MarkNonDiphtongs, Syllabify, TernaryFeet, BinaryFeet, MainStress, SecondaryStress, OptFinalStress))
+
+FinnProsody = hfst.compose((FinnWords, Rules))
+
+FinnProsody.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/Lingala.hfst.py b/test/tools/fsmbook-tests/python-scripts/Lingala.hfst.py
new file mode 100644
index 0000000..c63020d
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/Lingala.hfst.py
@@ -0,0 +1,154 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+
+regex('Stems', "[ {bet} | {béb} | {bomb} | {bóndel} | {bóngol} | {bót} | {búk} | \
+ {fung} | {kabol} | {kang} | {kom} | {kund} | {kóm} | {lakis} | \
+ {lí}  | {lob} | {luk} | {ndim} | {palangan} | {pangwis} | {sál} | \
+ {sepel} | {sómb} | {tál} | {támbol} | {tambwis} | {tataban} | \
+ {tún} | {yébis} \
+]")
+
+regex('L', "[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|á|é|í|ó|ú]")
+
+regex('Person1', '[Per ":" 1]')
+regex('Person2', '[Per ":" 2]')
+regex('Person3', '[Per ":" 3]')
+regex('Number', '[Num ":" [Sg|Pl] ]')
+
+# define Gender [Gen ":" [[1["0"|1]|2|3|4|5|6|7|8|9] "." [1[4|5]|[1|9|10]a]]];
+regex('Gender3', '[Gen ":" [1 "." 2 | 1a "." 2 | 3 "." 4 | 5 "." 6 | 7 "." 8 | 9a "." "10a" | "10" | 11 "." 6 | 14 "." 6 | 15]]')
+ 
+# define Reflexive [No | Yes];
+
+# Passive: -am-
+# Causative: -is-
+# Reciprocal: -an-
+# Applicative:l -el-
+# Reversive: -ol-
+# Iterative: reduplication of the root or root plus other morpheme;
+#  the two copies are separated by -a-; the second copy of the root
+#  has low tone on the first syllable
+# That is, the order of the morphemes is: REV, CAUS, PASS, APPL, RECIP
+
+# alobaloba 'he/she speak SP ITER'
+# alíalia   'he eat SP ITER'
+
+regex('PastTense', '[Past ":" [Rec|Hist|MoreRem|MostRem]]')
+regex('PresTense', '[Pres ":" [Cont|Hab1|Hab2]]')
+regex('FutTense', '[Fut ":" [Immed|MostRem]]')
+
+# define Reflexive [Refl ":" [No|Yes]];
+regex('Tense', '[Tns ":" [PastTense|PresTense|FutTense]]')
+# define Polarity [Pol ":" [Pos|Neg]];
+
+regex('Agreement', ' [[[Person1 | Person2] " " Number] | [Person3 " " Number " " Gender3]]')
+
+                
+# For Gender 15 we have only singular subject marker, no plural
+# and no object markers. Missing info?
+
+regex('SubjAgr', '[Sub ":" Agreement]  - [$Pl & $15]')
+regex('ObjAgr', '[Obj ":" Agreement] - $15 ')
+regex('Agr', '[Func ":" Agreement]')
+
+#define Features [SubjAgr " " ObjAgr " "  Tense " " Polarity];
+
+regex('Features', '[SubjAgr " " ObjAgr " " Tense]')
+
+regex('VerbLex', '"<" Stems "," Features ">" ')
+
+# Common singular agreement markers.
+
+regex('RAgr1', '[[. .] -> {mo} || "<" _ [$[Agr & $Person3 & $Sg & $4]]]')
+regex('RAgr2', '[[. .] -> {li} || "<" _ [$[Agr & $Person3 & $Sg & $5]]]')
+regex('RAgr3', '[[. .] -> e  || "<" _ [$[Agr & $Person3 & $Sg & $[9a "." "10a"]]]]')
+regex('RAgr4', '[[. .] -> {lo} || "<" _ [$[Agr & $Person3 & $Sg & $["10"|11]]]]')
+regex('RAgr5', '[[. .] -> {bo} || "<" _ [$[Agr & $Person3 & $Sg & $14]]]')
+# Common plural agreement markers
+
+regex('RAgr6', '[[. .] -> {bo} || "<" _ [$[Agr & $Person2 & $Pl]]] ')
+regex('RAgr7', '[[. .] -> {ba} || "<" _ [$[Agr & $Person3 & $Pl & $2]]]')
+regex('RAgr8', '[[. .] -> {mi} || "<" _ [$[Agr & $Person3 & $Pl & $4]]]')
+regex('RAgr9', '[[. .] -> {ma} || "<" _ [$[Agr & $Person3 & $Pl & $[5|6]]]]')
+regex('RAgr10', '[[. .] -> {bi}  || "<" _ [$[Agr & $Person3 & $Pl & $7]]]')
+regex('RAgr11', '[[. .] -> i  || "<" _ [$[Agr & $Person3 & $Pl & $[9a|"10"]]]]')
+
+# Rule Block 1
+# Singular specific subject markers
+
+regex('R101', '[[. .] -> {na} || "<" _ [$[SubjAgr & $Person1 & $Sg]]] ')
+regex('R102', '[[. .] -> o || "<" _ [$[SubjAgr & $Person2 & $Sg]]] ')
+regex('R103', '[[. .] -> a || "<" _ [$[SubjAgr & $Person3 & $Sg & $2]]]')
+regex('R104', '[[. .] -> e  || "<" _ [$[SubjAgr & $Person3 & $Sg & $7]]]')
+regex('R105', '[[. .] -> {ei} || "<" _[$[SubjAgr & $Person3 & $Sg & $15]]]')
+
+# Rules of referral for singular subject markers
+regex('R106', '`[RAgr1, Func, Sub]')
+regex('R107', '`[RAgr2, Func, Sub]')
+regex('R108', '`[RAgr3, Func, Sub]')
+regex('R109', '`[RAgr4, Func, Sub]')
+regex('R110', '`[RAgr5, Func, Sub]')
+# Plural specific subject markers
+
+regex('R111', '[[. .] -> {to} || "<" _ [$[SubjAgr & $Person1 & $Pl]]] ')
+
+# Rules of referral for plural subject markers.
+
+regex('R112', '`[RAgr6, Func, Sub]')
+regex('R113', '`[RAgr7, Func, Sub]')
+regex('R114', '`[RAgr8, Func, Sub]')
+regex('R115', '`[RAgr9, Func, Sub]')
+regex('R116', '`[RAgr10, Func, Sub]')
+regex('R117', '`[RAgr11, Func, Sub]')
+
+regex('R201', '[[. .] -> {ko} || "<" _ [$[Fut":"Immed]]] ')
+
+# Singular specific object markers
+
+regex('R301', '[[. .] -> n || "<" _ [$[ObjAgr & $Person1 & $Sg]]] ')
+regex('R302', '[[. .] -> {ko} || "<" _ [$[ObjAgr & $Person2 & $Sg]]] ')
+regex('R303', '[[. .] -> {mo} || "<" _ [$[ObjAgr & $Person3 & $Sg & $2]]]')
+regex('R304', '[[. .] -> {ei}  || "<" _ [$[ObjAgr & $Person3 & $Sg & $7]]]')
+
+# Rules of referral for singular object markers
+
+regex('R305', '`[RAgr1, Func, Obj]')
+regex('R306', '`[RAgr2, Func, Obj]')
+regex('R307', '`[RAgr3, Func, Obj]')
+regex('R308', '`[RAgr4, Func, Obj]')
+regex('R309', '`[RAgr5, Func, Obj]')
+
+# Plural specific object markers
+
+regex('R310', '[[. .] -> {lo} || "<" _ [$[ObjAgr & $Person1 & $Pl]]] ')
+
+# Rules of referral for plural object markers
+
+regex('R311', '`[RAgr6, Func, Obj]')
+regex('R312', '`[RAgr7, Func, Obj]')
+regex('R313', '`[RAgr8, Func, Obj]')
+regex('R314', '`[RAgr9, Func, Obj]')
+regex('R315', '`[RAgr10, Func, Obj]')
+regex('R316', '`[RAgr11, Func, Obj]')
+
+# Tense rules
+regex('R401', '[[. .] -> {ak} || _ "," [$[Pres ":" [Hab1|Hab2]| Past ":" [Hist|MostRem]]]]')
+regex('R402', '[[. .] -> a    || _ "," [$[Pres ":" Cont|Fut ":" Immed]]]')
+
+regex('R501', '[[. .] -> i || _ "," [$[Fut ":" MostRem|Past ":" [Rec|Hist]]]]')
+
+# Eliminate Features and auxiliary symbols from the lower side.
+regex('Cleanup', '\\L -> 0')
+
+# Build the Lingala Verb Transducer
+Result = regex(None, 'VerbLex .o. R301 .o. R302 .o. R303 .o. R304 .o. R305 .o. R306 .o. R307 .o. R308 .o. R309 .o. R310 .o. R311 .o. R312 .o. R313 .o. R314 .o. R315 .o. R316 .o. R201 .o. R101 .o. R102 .o. R103 .o. R104 .o. R105 .o. R106 .o. R107 .o. R108 .o. R109 .o. R110 .o. R111 .o. R112 .o. R113 .o. R114 .o. R115 .o. R116 .o. R117 .o. R401 .o. R402 .o. R501 .o. Cleanup ')
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/MonishAnalysis.hfst.py b/test/tools/fsmbook-tests/python-scripts/MonishAnalysis.hfst.py
new file mode 100644
index 0000000..872c3d6
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/MonishAnalysis.hfst.py
@@ -0,0 +1,48 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+
+regex('FrontV', '[ i | e | é | ä ]')
+
+regex('BackV', '[ u | o | ó | a ]')
+
+regex('MorphoV', '[ %^U | %^O | %^Ó | %^A ]')
+
+regex('Root', '[ r u u z o d | t s a r l ó k | n t o n ó l | b u n o o t s | \
+v é s i i m b | y ä ä q i n | f e s é é n g ]')
+
+regex('Suff1', '[ %+Int .x. [ %^U %^U k ] ]')
+
+regex('Suff2', '[ %+Perf .x. [ %^O n ] ] | \
+[ %+Imperf .x. [ %^Ó m b ] ] | \
+[ %+Opt .x. [ %^U d d ] ] ')
+
+regex('Suff3', '[ %+True .x. [ %^A n k ] ] | \
+[ %+Belief .x. [ %^A %^A v %^O  t ] ] | \
+[ %+Doubt .x. [ %^U %^U z ] ] | \
+[ %+False .x. [ %^Ó q ] ] ')
+
+regex('Suff4', '[ %+1P %+Sg .x. %^A %^A b %^A ] | \
+		[ %+2P %+Sg .x. %^Ó m %^A ] | \
+		[ %+3P %+Sg .x. %^U v v %^U ] | \
+		[ %+1P %+Pl %+Excl .x. %^A %^A b %^O r %^A ] | \
+		[ %+1P %+Pl %+Incl .x. %^A %^A b %^U g %^A ] | \
+		[ %+2P %+Pl .x. %^Ó m %^O r %^A ] | \
+		[ %+3P %+Pl .x. %^U v v %^O r %^U ]')
+	     
+Rule1 = regex(None, '[ %^U -> u , %^O -> o , %^Ó -> ó , %^A -> a || BackV ?* _ ]')
+
+Rule2 = regex(None, '[ %^U -> i , %^O -> e , %^Ó -> é , %^A -> ä ]')
+
+tmp = regex(None, '[ Root (Suff1) Suff2 (Suff3) Suff4 ]')
+
+Result = hfst.compose((tmp, Rule1, Rule2))
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/MonishGuesserAnalyzer.hfst.py b/test/tools/fsmbook-tests/python-scripts/MonishGuesserAnalyzer.hfst.py
new file mode 100644
index 0000000..d941fef
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/MonishGuesserAnalyzer.hfst.py
@@ -0,0 +1,37 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+
+
+regex('FrontV', '[ i | e | é | ä ]')
+
+regex('BackV', '[ u | o | ó | a ]')
+
+regex('MorphoV', '[ %^U | %^O | %^Ó | %^A ]')
+
+regex('Root', '[ [ ? - [ BackV | MorphoV ] ]+ & $[ FrontV ] ] | [ [ ? - [ FrontV | MorphoV ] ]+ & $[ BackV ] ]')
+      
+regex('Suff1', '[ %+Int .x. [ %^U %^U k ] ]')
+
+regex('Suff2', '[ %+Perf .x. [ %^O n ] ] | [ %+Imperf .x. [ %^Ó m b ] ] | [ %+Opt .x. [ %^U d d ] ]')
+
+regex('Suff3', '[ %+True .x. [ %^A n k ] ] | [ %+Belief .x. [ %^A %^A v %^O  t ] ] |[ %+Doubt .x. [ %^U %^U z ] ] | [ %+False .x. [ %^Ó q ] ]')
+
+regex('Suff4', '[ %+1P %+Sg .x. %^A %^A b %^A ] | [ %+2P %+Sg .x. %^Ó m %^A ] | [ %+3P %+Sg .x. %^U v v %^U ] | [ %+1P %+Pl %+Excl .x. %^A %^A b %^O r %^A ] | [ %+1P %+Pl %+Incl .x. %^A %^A b %^U g %^A ] | [ %+2P %+Pl .x. %^Ó m %^O r %^A ] | [ %+3P %+Pl .x. %^U v v %^O r %^U ]')
+
+Rule1 = regex(None, '[ %^U -> u , %^O -> o , %^Ó -> ó , %^A -> a || BackV ?* _ ]')
+
+Rule2 = regex(None, '[ %^U -> i , %^O -> e , %^Ó -> é , %^A -> ä ]')
+
+tmp = regex(None, '[ Root (Suff1) Suff2 (Suff3) Suff4 ]')
+
+Result = hfst.compose((tmp, Rule1, Rule2))
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/NumbersToNumerals.hfst.py b/test/tools/fsmbook-tests/python-scripts/NumbersToNumerals.hfst.py
new file mode 100644
index 0000000..27871d5
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/NumbersToNumerals.hfst.py
@@ -0,0 +1,60 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)                
+
+# From one to nine.
+
+OneToNine = hfst.fst({'1':'one',
+                      '2':'two',
+                      '3':'three',
+                      '4':'four',
+                      '5':'five',
+                      '6':'six',
+                      '7':'seven',
+                      '8':'eight',
+                      '9':'nine'})
+
+# Numbers to prefixes that can preceed "-teen" or "-ten".
+
+TeenTen = hfst.fst({'3':'thir',
+                    '5':'fif',
+                    '6':'six',
+                    '7':'seven',
+                    '8':'eigh',
+                    '9':'nine'})
+
+# Special numbers.
+
+Special = hfst.fst({'10':'ten',
+                    '11':'eleven',
+                    '12':'twelve',
+                    '14':'fourteen'})
+
+# Here we handle ordinary teens and disjunct them with the special numbers.
+
+Epsilon2Teen = hfst.fst({'':'teen'})
+One2Epsilon = hfst.fst({'1':''})
+Teens_ = hfst.concatenate((One2Epsilon, TeenTen, Epsilon2Teen))
+Teens = hfst.disjunct((Special, Teens_))
+
+# Special stems.
+
+TenStem = hfst.disjunct((hfst.fst({'2':'twen', '4':'for'}), TeenTen))
+
+# TenStem is followed either by "ty" paired with a zero or by "ty-" mapped to an epsilon and followed by one number.
+
+TMP = hfst.concatenate((hfst.fst({'':'ty-'}), OneToNine))
+Tens = hfst.concatenate((TenStem, hfst.disjunct((hfst.fst({'0':'ty'}), TMP))))
+
+# We finally disjunct all numbers.
+
+Result = hfst.disjunct((OneToNine, Teens, Tens))
+Result.minimize()
+Result.write_to_file('Result')
diff --git a/test/tools/fsmbook-tests/python-scripts/Palindromes.hfst.py b/test/tools/fsmbook-tests/python-scripts/Palindromes.hfst.py
new file mode 100644
index 0000000..6fbf1d7
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/Palindromes.hfst.py
@@ -0,0 +1,46 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+# We first construct BidirEnglish that
+# contains all the words whose reverse is also a word of English,
+# for example, "madam" and "dog". We wish to keep "madam" (reversed "madam") and
+# eliminate "dog" (reversed "god").
+
+with open('lexicon/english_lexicon.txt') as f:
+    words = f.readlines()
+English = hfst.fst(words)
+English.substitute('\n', hfst.EPSILON)
+English.minimize()
+
+# We intersect English with its reverse. We only take into account
+# words that contain at least two characters. (Words like "a"
+# and "I" are not interesting here.)
+
+MinTwoChars = hfst.regex('[? ?+]')
+
+RevEnglish = English.copy()
+RevEnglish.reverse()
+
+BidirEnglish = hfst.intersect((English, RevEnglish, MinTwoChars))
+BidirEnglish.minimize()
+
+# Next we print all strings recognized by =BidirPaths= and construct a stream
+# of transducers where each transducer contains one string recognized
+# by =BidirPaths=. Then we create a corresponding stream of reversed transducers and
+# conjunct the streams. The resulting stream will contain transducers that
+# represent a palindrom (e.g. "madam") and empty transducers (e.g. the transducers
+# resulting from the intersection of "dog" and "god" and vice versa).
+
+bidir_paths = BidirEnglish.extract_paths()
+Result = hfst.empty_fst()
+for path in bidir_paths:
+    tr1 = hfst.fst(path)
+    tr2 = tr1.copy()
+    tr2.reverse()
+    tr2.minimize()
+    TR = hfst.intersect((tr1, tr2))
+    Result.disjunct(TR)
+
+Result.minimize()
+Result.write_to_file('Result')
+
+
diff --git a/test/tools/fsmbook-tests/python-scripts/PlusOrMinus.hfst.py b/test/tools/fsmbook-tests/python-scripts/PlusOrMinus.hfst.py
new file mode 100644
index 0000000..05dcc82
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/PlusOrMinus.hfst.py
@@ -0,0 +1,49 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+verbose_regex=False
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+        if verbose_regex:
+            print("defined transducer '" + expression + "':")
+            print(tr)
+
+regex('N', '[1|2|3|4|5|6|7|8|9]')
+regex('Z', '["0" | N]')
+
+# Insert an initial 1 in front of a sequence of zeros. To make
+# this relation functional in both directions, we need two
+# replace expressions. One introduces 1, the other removes 1.
+# The composition of the two is a relation that uniquely maps,
+# for example, 100 to 99 and, conversely, 99 to 100.
+
+regex('CarryUp', '[ 1 <- [. .] || .#. _ "0"+ .#. ] .o.  [ 1 -> 0 || .#. _ "0"+ .#. ]')
+
+regex('AddUp', ' [ 1 <- "0", 2 <- 1, 3 <- 2, 4 <- 3,  5  <- 4, 6 <-  5 , 7 <- 6, 8 <- 7, 9 <- 8, "0" <- 9 || .#. ("+") Z* _ 9* .#. ]')
+
+regex('NoLeadingZero', ' [ "0" => .#. N Z* _ , .#. _ .#. ]')
+
+# PlusOrMinusOne.hfst maps any natural number N to (N-1), and vice versa.
+
+regex('PlusOrMinusOne', 'CarryUp .o. AddUp .o. NoLeadingZero')
+regex('PlusOrMinusTwo', 'PlusOrMinusOne .o. PlusOrMinusOne')
+regex('PlusOrMinusThree', 'PlusOrMinusTwo .o. PlusOrMinusOne')
+regex('PlusOrMinusFour', 'PlusOrMinusThree .o. PlusOrMinusOne')
+regex('PlusOrMinusFive', 'PlusOrMinusFour .o. PlusOrMinusOne')
+regex('PlusOrMinusSix', 'PlusOrMinusFive .o. PlusOrMinusOne')
+regex('PlusOrMinusSeven', 'PlusOrMinusSix .o. PlusOrMinusOne')
+regex('PlusOrMinusEight', 'PlusOrMinusSeven .o. PlusOrMinusOne')
+regex('PlusOrMinusNine', 'PlusOrMinusEight .o. PlusOrMinusOne')
+regex('PlusOrMinusTen', 'PlusOrMinusNine .o. PlusOrMinusOne')
+
+ostr = hfst.HfstOutputStream(filename='Result')
+for i in ('One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'):
+    ostr.write(regex(None, 'PlusOrMinus' + i))
+ostr.flush()
+ostr.close()
diff --git a/test/tools/fsmbook-tests/python-scripts/YaleShooting.hfst.py b/test/tools/fsmbook-tests/python-scripts/YaleShooting.hfst.py
new file mode 100644
index 0000000..a5a9986
--- /dev/null
+++ b/test/tools/fsmbook-tests/python-scripts/YaleShooting.hfst.py
@@ -0,0 +1,114 @@
+exec(compile(open('CompileOptions.py', 'rb').read(), 'CompileOptions.py', 'exec'))
+
+comp = hfst.XreCompiler(hfst.get_default_fst_type())
+
+def regex(name, expression):
+    tr = comp.compile(expression)
+    if name == None:
+        return tr
+    else:
+        comp.define_transducer(name, tr)
+
+# We start our version of the Yale Shooting xfst script with a few simple 
+# definitions
+
+Proposition  = regex('Proposition', 'load | loaded | shoot | alive')
+Valuation  = regex('Valuation', '[%+ | %- | F] Proposition ')
+Frame  = regex('Frame', '%[ (Valuation [%, Valuation]*) %]')
+
+# With these definitions, the expression Frame+ describes an infinite language
+# of frame sequences including the one above for the Yale Shooting scenario.
+# In order to implement the constraints on inert fluents such as loaded and
+# alive, it is convenient to start with a few auxiliary definitions.
+
+Loaded  = regex('Loaded', 'Frame & $[%+ loaded] & ~$[%- loaded]')
+Load  = regex('Load', 'Frame & $[%+ load] & ~$[%- load]')
+Shoot  = regex('Shoot', 'Frame & $[%+ shoot] & ~$[%- shoot]')
+Alive  = regex('Alive', 'Frame & $[%+ alive] & ~$[%- alive]')
+FLoaded  = regex('FLoaded', 'Frame & $[F loaded]')
+FAlive  = regex('FAlive', 'Frame & $[F alive]')
+
+# Each of the definitions above is a constraint on frames denoting the set of
+# compatible frames. For example, Loaded picks out the frames where the gun
+# is loaded, FLoaded denotes the frames where the force F is applied to loaded.
+# The FLoaded frames may include +loaded or -loaded or neither. In the
+# following, the ordering of frames matters but the ordering of valuations
+# within a frame is irrelevant. For example, [+loaded,+alive] and 
+# [+alive,+loaded] are equivalent. In other words, frames are orderless
+# (= commutative), whereas sequences of frames are not.
+
+# The Inertia constraints on adjacent frames can be stated as follows. 
+# We start with loaded.
+
+InertLoaded = regex('InertLoaded', '[Loaded & ~FLoaded => _ Loaded | .#.] & [Loaded => .#. | Loaded | FLoaded _ ]')
+
+# The constraint consists of two restrictions. The first restriction says that a frame that contains +loaded and doesn't contain Floaded must be followed by a frame containing +loaded unless it is the last frame of the sequence. The second constraint says that a frame containing +loaded must be preceded by a frame containing +loaded or Floaded (possibly both) unless it is the first frame of the sequence. The first restriction prohibits frame pairs such as [+loaded][-loaded] where loadedn [...]
+
+# The inertness constraint on alive has the same form:
+
+InertAlive = regex('InertAlive', '[Alive & ~FAlive => _ Alive | .#.] & [Alive => .#. | Alive | FAlive _ ]')
+
+# To express the idea that a +load action in a frame enables +loaded in the next frame, we need a constraint that forces Floaded to be included in every frame that contains +load. Unlike the two inert rules that constrain pairs of adjacent frames, the next three principles constrain single frames.
+
+LoadFLoaded  = regex('LoadFLoaded', '~[Load & ~FLoaded]')
+
+# A frame such as [+load] is not allowed. To satisfy the constraint it must be expanded to [+load,Floaded] or reduced to []. Similarly, we want to say that shooting is always potentially life-threatening:
+
+ShootFAlive  = regex('ShootFAlive', '~[Shoot & ~FAlive]')
+
+# The ShootFAlive constraint prohibits frames such as [+alive,+shoot] where +shoot appears without Falive. Unless we are shooting with a fully loaded revolver, firing a gun might make the gun unloaded, so we need:
+
+ShootFLoaded  = regex('ShootFLoaded', '~[Shoot & ~FLoaded]')
+
+# To show that the five constraints, InertLoaded, InertAlive, LoadFLoaded, ShootFAlive, ShootFLoaded, have the intended effect, we can start with a partial description of the Yale Shooting problem. In the initial frame the target is alive and the gun unloaded. In the second frame the gun is loaded. After zero or more frames, a shooting occurs.
+
+YaleShooting  = regex('YaleShooting', '[Alive & ~Loaded] Load Frame* Shoot Frame')
+
+# The above description is incomplete in that the four or more frames in the sequence to not constrain each other in any way. Only three frames are partially specified. In order to enforce the principles we have set up, we intersect this underspecified frame sequence with our five contstraints:
+
+Result = regex(None, 'YaleShooting & InertLoaded & InertAlive & LoadFLoaded & ShootFAlive & ShootFLoaded')
+Result.minimize()
+Result.write_to_file('Result')
+
+# The resulting network contains an infinite number of valid instantiations of the Yale Shooting scenario. For example, it includes the following frame sequence where the target dies:
+
+# [+alive,-loaded]
+# [+load,Floaded,+alive]
+# [+loaded,+alive]
+# [+loaded,+shoot,Floaded,Falive,+alive]
+# [-alive]
+
+# It also includes a frame sequence just like the one above with [+alive] as the last frame. This is a case where the shot missed and the target survived. An empty frame, [], is also a legal terminating frame for the case where we do not know whether the target is still alive.
+
+# Here are some examples of illegal frame sequences that are eliminated by the constraints.
+
+# [+alive,-loaded]
+# [+load,Floaded,+alive]
+# [+loaded,+alive]
+# [+loaded,+shoot,Floaded,Falive]
+# []
+
+# The above sequence fails because +alive is missing in Frame 4 in violation of the InertAlive constraint because +alive is included in the preceding frame.
+
+# [+alive,-loaded]
+# [+load,Floaded,+alive]
+# [+alive]
+# [+loaded,+shoot,Floaded,Falive,+alive]
+# []
+
+# In the above case, Frame 3 should contain +loaded as required by InertLoaded because +loaded appears in the next frame.
+
+# [+alive,-loaded]
+# [+load,Floaded,+alive]
+# [+loaded,+alive]
+# [+loaded,+shoot,Falive,+alive]
+# []
+
+# This last example lacks Floaded in Frame 4, required by ShootFLoaded because of the inclusion of +shoot in the same frame.
+
+# To experiment with this script you can load a plain uncommented text version of the script from YaleShooting.txt. Place it in a directory where you can launch it with the simple command xfst -l YaleShooting.txt.
+
+# References
+# Tim Fernando and Rowan Nairn. Entailments in finite-state temporality. IWCS-6. Tilburg. 2005.
+# Steve Hanks and Drew McDermott. Nonmonotonic logic and temporal projection. Artificial Intelligence 33(3):379-412.1987.
+
diff --git a/test/tools/fsmbook-tests/test.sh b/test/tools/fsmbook-tests/test.sh
index 24be9e1..705a4b8 100755
--- a/test/tools/fsmbook-tests/test.sh
+++ b/test/tools/fsmbook-tests/test.sh
@@ -1,3 +1,15 @@
+
+if [ "$1" = "-h" -o "$1" = "--help" ]; then
+    echo ""
+    echo "Usage: "$0" [TESTNAME] [--python PYTHON] [--pythonpath PYTHONPATH]"
+    echo ""
+    echo "  TESTNAME: The name of the test that will be run. If not given, all tests are run."
+    echo "    PYTHON: Python that is used to run the tests instead of hfst-xfst (e.g. 'python3.5')."
+    echo "PYTHONPATH: Path that is prepended to sys.path when running tests with python (with --python)."
+    echo ""
+    exit 0
+fi
+
 # check for programs
 
 COMPILE_FROM_SCRATCH="false"
@@ -5,14 +17,11 @@ COMPILE_XFST_SCRIPT="true"
 COMPILE_HFST_SCRIPT="true"
 EXIT_IF_NOT_EQUIVALENT="true"
 
+PYTHON=""
+PYTHONPATH=""
+
 HFST_TOOL="../../../tools/src/parsers/hfst-xfst"
 
-if [ "$COMPILE_XFST_SCRIPT" = "true" ]; then
-    if ! (ls $HFST_TOOL > /dev/null); then
-        echo "ERROR: Could not find "$HFST_TOOL" that is needed to run the tests"
-        exit 1
-    fi
-fi
 if [ "$COMPILE_FROM_SCRATCH" = "true" ]; then
     if ! (which xfst > /dev/null); then
         echo "ERROR: Could not find program 'xfst' that is needed to run the tests"
@@ -46,14 +55,42 @@ examples="BetterColaMachine BrazilianPortuguese1 BrazilianPortuguese2 EnglishNum
 "MonishAnalysis MonishGuesserAnalyzer NumbersToNumerals PlusOrMinus FinnishNumerals "\
 "YaleShooting FinnishProsody Palindromes EinsteinsPuzzle"
 
-if ! [ "$1" = "" ]; then
-    examples=$1
+if [ "$1" = "--python" ]; then
+    PYTHON=$2
+    if [ "$3" = "--pythonpath" ]; then
+	PYTHONPATH=$4
+    fi
+else
+    if ! [ "$1" = "" ]; then
+	examples=$1
+    fi
+    if [ "$examples" = "FinnishNumerals" ]; then
+	echo "FinnishNumerals depends on NumbersToNumerals, running tests for both"
+	examples="NumbersToNumerals FinnishNumerals"
+    fi
+fi
+
+if [ "$2" = "--python" ]; then
+    PYTHON=$3
+    if [ "$4" = "--pythonpath" ]; then
+	PYTHONPATH=$5
+    fi
+fi
+
+if [ "$PYTHON" == "" ]; then
+    if [ "$COMPILE_XFST_SCRIPT" = "true" ]; then
+	if ! (ls $HFST_TOOL > /dev/null); then
+            echo "ERROR: Could not find "$HFST_TOOL" that is needed to run the tests"
+            exit 1
+	fi
+    fi
 fi
 
 for example in $examples;
 do
     echo "Testing "$example"..."
 
+    # If flags must be eliminated when comparing the results
     if [ "$example" = "EsperantoAdjectives" -o \
         "$example" = "EsperantoNounsAdjectivesAndVerbs" -o \
         "$example" = "EsperantoNounsAndAdjectivesWithTags" -o \
@@ -64,108 +101,160 @@ do
     else
         compare_flags="-q"
     fi
-    
-    # (1) If xfst solution exists,
-    if ! [ "$example" = "FinnishNumerals" -o \
-        "$example" = "FinnishProsody" -o \
-        "$example" = "Palindromes" ]; then
 
-        # compile with xfst/foma, if needed..
-        if [ "$COMPILE_FROM_SCRATCH" = "true" ]; then
-            if [ "$example" = "FinnishOTProsody" -o \
-                "$example" = "Lingala" -o \
-                "$example" = "DateParser" -o \
-                "$example" = "YaleShooting" ]; then
-                if [ "$example" = "DateParser" ] ; then
-                    echo "  compiling with foma (result from xfst will not be equivalent"
-                    echo "  because symbols enclosed in square brackets are not harmonized)"
-                else
-                    echo "  compiling with foma (result from xfst will be too big)"
-                fi
-                if ! ($FOMA -f xfst-scripts/$example.xfst.script > /dev/null 2> LOG); then
-                    echo "ERROR: compiling with foma failed"
-                    cat LOG
-                    exit 1
-                fi
+    # Check if xfst solution exists
+    XFST_SOLUTION_EXISTS="true"
+    if [ "$example" = "FinnishNumerals" -o \
+	 "$example" = "FinnishProsody" -o \
+	 "$example" = "Palindromes" ]; then
+	XFST_SOLUTION_EXISTS="false";
+    fi
+
+    # (1) Generate or copy the expected result to file 'Expected_result'
+    if [ "$COMPILE_FROM_SCRATCH" = "true" -a "$XFST_SOLUTION_EXISTS" = "true" ]; then
+	# if foma must be used instead of xfst
+        if [ "$example" = "FinnishOTProsody" -o \
+			"$example" = "Lingala" -o \
+			"$example" = "DateParser" -o \
+			"$example" = "YaleShooting" ]; then
+            if [ "$example" = "DateParser" ] ; then
+                echo "  compiling with foma (result from xfst will not be equivalent"
+                echo "  because symbols enclosed in square brackets are not harmonized)"
             else
-                echo "  compiling with xfst.."
-                if ! ($XFST -f xfst-scripts/$example.xfst.script 2> LOG); then
-                    echo "ERROR: compiling with xfst failed"
-                    cat LOG
-                    exit 1;
-                fi
+                echo "  compiling with foma (result from xfst will be too big)"
             fi
-        else
-            if ! [ -e expected-results/$example.prolog ]; then
-                echo "ERROR: file expected-results/"$example".prolog missing"
+            if ! ($FOMA -f xfst-scripts/$example.xfst.script > /dev/null 2> LOG); then
+                echo "ERROR: compiling with foma failed"
+                cat LOG
                 exit 1
-            else
-                cp expected-results/$example.prolog Result
+            fi
+        else
+            echo "  compiling with xfst.."
+            if ! ($XFST -f xfst-scripts/$example.xfst.script 2> LOG); then
+                echo "ERROR: compiling with xfst failed"
+                cat LOG
+                exit 1;
             fi
         fi
-
-        # and convert from prolog to openfst-tropical for comparing.
-        cp Result Result.prolog
-        if ! (cat Result | $tooldir/hfst-txt2fst --prolog -f $common_format > tmp && \
-            mv tmp Result_from_xfst); then
+    else
+        if ! [ -e expected-results/$example.prolog ]; then
+            echo "ERROR: file expected-results/"$example".prolog missing"
+            exit 1
+        else
+            cp expected-results/$example.prolog Result
+        fi
+    fi
+    # convert from prolog to openfst-tropical for comparing.
+    cp Result Result.prolog
+    if ! [ "$PYTHON" == "" ]; then
+	if ! (cat Result | $PYTHON prolog2fst.py $common_format $PYTHONPATH > tmp && \
+		     mv tmp Expected_result); then
             echo "ERROR: in converting result from xfst/foma to hfst format"
             exit 1;
-        fi
-	rm -f Result.prolog
-
-        # Also compile with hfst-xfst using all back-end formats..
-        if [ "$COMPILE_XFST_SCRIPT" == "true" ]; then
+	fi
+    else
+	if ! (cat Result | $tooldir/hfst-txt2fst --prolog -f $common_format > tmp && \
+		     mv tmp Expected_result); then
+            echo "ERROR: in converting result from xfst/foma to hfst format"
+            exit 1;
+	fi
+    fi
+    rm -f Result.prolog
+    # The expected result is now in file 'Expected_result' in prolog format
+    
+    # (2) Compile with hfst-xfst or hfst python api using all back-end formats..
+    if [ "$COMPILE_XFST_SCRIPT" == "true" -a "$XFST_SOLUTION_EXISTS" = "true" ]; then
         for format in $backend_formats; 
         do
-            if ! [ -x $HFST_TOOL ]; then
-                echo "  warning: skipping compilation with hfst-xfst, assuming configured off"
-                continue;
-            fi
-            if (! $tooldir/hfst-format --list-formats | grep $format > /dev/null); then
-                echo "  skipping compilation with hfst-xfst using back-end format "$format" as it is not available"
-                continue;
-            fi
-            echo "  compiling with hfst-xfst using back-end format "$format".."
-            if ! ($HFST -f $format -F xfst-scripts/$example.xfst.script); then
-                echo "ERROR: compilation with hfst-xfst failed"
-                cat LOG;
-                exit 1;
-            fi
-            # and convert from prolog to openfst-tropical and compare the results.
-            if ! (cat Result | $tooldir/hfst-txt2fst --prolog -f $common_format > tmp && \
-                mv tmp Result_from_hfst_xfst); then
-                echo "ERROR: in converting result from hfst prolog to binary format"
-                exit 1;
-            fi
-            if ! ($tooldir/hfst-compare $compare_flags Result_from_xfst Result_from_hfst_xfst); then
-                echo "FAIL: results from xfst and hfst-xfst ("$format") are not equivalent, storing results in files:"
-                echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
-                echo "    log/"$example.result_from_hfst_xfst_using_backend_format_$format
-                if ! [ -d log ]; then
-                    mkdir log
-                fi
-                cp Result_from_xfst log/$example.result_from_xfst_script_using_xfst_tool
-                cp Result_from_hfst_xfst log/$example.result_from_hfst_xfst_using_backend_format_$format
-                if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+	    if ! [ "$PYTHON" == "" ]; then
+		if (! $PYTHON list_formats.py $PYTHONPATH | grep $format > /dev/null); then
+                    echo "  skipping compilation with hfst-xfst using back-end format "$format" as it is not available"
+                    continue;
+		fi
+		echo "  compiling xfst with HFST python API using back-end format "$format".."
+		if ! ($PYTHON compile_xfst.py $format xfst-scripts/$example.xfst.script $PYTHONPATH); then
+		    echo "ERROR: compilation of xfst with HFST python API failed"
+		    cat LOG;
+		    exit 1;
+		fi
+	    else
+		if ! [ -x $HFST_TOOL ]; then
+                    echo "  warning: skipping compilation with hfst-xfst, assuming configured off"
+                    continue;
+		fi
+		if (! $tooldir/hfst-format --list-formats | grep $format > /dev/null); then
+                    echo "  skipping compilation with hfst-xfst using back-end format "$format" as it is not available"
+                    continue;
+		fi
+		echo "  compiling with hfst-xfst using back-end format "$format".."
+		if ! ($HFST -f $format -F xfst-scripts/$example.xfst.script); then
+                    echo "ERROR: compilation with hfst-xfst failed"
+                    cat LOG;
                     exit 1;
-                fi
-            fi
+		fi
+	    fi
+            # and convert from prolog to openfst-tropical and compare the results.
+	    if ! [ "$PYTHON" == "" ]; then
+		if ! (cat Result | $PYTHON prolog2fst.py $common_format $PYTHONPATH > tmp && \
+			     mv tmp Result_from_hfst_xfst); then
+		    echo "ERROR: in converting result from hfst prolog to binary format"
+		    exit 1;
+		fi
+	    else
+		if ! (cat Result | $tooldir/hfst-txt2fst --prolog -f $common_format > tmp && \
+			     mv tmp Result_from_hfst_xfst); then
+		    echo "ERROR: in converting result from hfst prolog to binary format"
+		    exit 1;
+		fi
+	    fi
+	    if ! [ "$PYTHON" = "" ]; then
+		if ! ($PYTHON compare.py Expected_result Result_from_hfst_xfst $compare_flags $PYTHONPATH); then
+		    echo "FAIL: results from xfst and hfst-xfst ("$format") are not equivalent, storing results in files:"
+                    echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
+                    echo "    log/"$example.result_from_hfst_xfst_using_backend_format_$format
+                    if ! [ -d log ]; then
+			mkdir log
+                    fi
+                    cp Expected_result log/$example.result_from_xfst_script_using_xfst_tool
+                    cp Result_from_hfst_xfst log/$example.result_from_hfst_xfst_using_backend_format_$format
+                    if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+			exit 1;
+                    fi
+		fi
+	    else
+		if ! ($tooldir/hfst-compare $compare_flags Expected_result Result_from_hfst_xfst); then
+                    echo "FAIL: results from xfst and hfst-xfst ("$format") are not equivalent, storing results in files:"
+                    echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
+                    echo "    log/"$example.result_from_hfst_xfst_using_backend_format_$format
+                    if ! [ -d log ]; then
+			mkdir log
+                    fi
+                    cp Expected_result log/$example.result_from_xfst_script_using_xfst_tool
+                    cp Result_from_hfst_xfst log/$example.result_from_hfst_xfst_using_backend_format_$format
+                    if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+			exit 1;
+                    fi
+		fi
+	    fi
 	    rm -f Result_from_hfst_xfst
         done
-        fi
-
     fi
 
-    # (2) Compile hfst script with all back-end formats and compare the results..
+    # (3) Compile hfst script with all back-end formats and compare the results..
     if [ "$COMPILE_HFST_SCRIPT" = "true" ]; then
     for format in $backend_formats; 
     do
-        if (! $tooldir/hfst-format --list-formats | grep $format > /dev/null); then
-            echo "  skipping compilation of hfst script using back-end format "$format" as it is not available"
-            continue;
-        fi
-
-        echo "  compiling hfst script with back-end format "$format".."
+	if ! [ "$PYTHON" == "" ]; then
+	    if (! $PYTHON list_formats.py $PYTHONPATH | grep $format > /dev/null); then
+		echo "  skipping compilation of hfst script using back-end format "$format" as it is not available"
+		continue;
+            fi
+	else
+            if (! $tooldir/hfst-format --list-formats | grep $format > /dev/null); then
+		echo "  skipping compilation of hfst script using back-end format "$format" as it is not available"
+		continue;
+            fi
+	fi
 
         if [ "$example" = "FinnishNumerals" ]; then
             if ! [ -f tmpdir/NumbersToNumerals ]; then
@@ -175,110 +264,149 @@ do
             fi
         fi
 
-        if ! ($SH hfst-scripts/$example.hfst.script $format $tooldir); then
-            echo "ERROR: compilation of hfst script failed"
-            exit 1
-        fi
-        cat Result | $tooldir/hfst-fst2fst -f $common_format > tmp
+	if ! [ "$PYTHON" == "" ]; then
+	    if [ -e python-scripts/$example.hfst.py ]; then
+		echo "  compiling script with HFST python API using back-end format "$format".."
+		if ! ($PYTHON python-scripts/$example.hfst.py $format $PYTHONPATH); then
+		    echo "ERROR: compilation of script with HFST python API failed"
+		    cat LOG;
+		    exit 1;
+		fi
+	    else
+		echo "  no python script found for "$example", using hfst script instead"
+		if ! ($SH hfst-scripts/$example.hfst.script $format $tooldir); then
+		    echo "ERROR: compilation of hfst script failed"
+		    exit 1
+		fi
+            fi
+	else
+	    echo "  compiling hfst script with back-end format "$format".."
+            if ! ($SH hfst-scripts/$example.hfst.script $format $tooldir); then
+		echo "ERROR: compilation of hfst script failed"
+		exit 1
+            fi
+	fi
+	if ! [ "$PYTHON" = "" ]; then
+	    cat Result | $PYTHON fst2fst.py $common_format $PYTHONPATH > tmp
+	else
+            cat Result | $tooldir/hfst-fst2fst -f $common_format > tmp
+	fi
         mv tmp Result_from_hfst_script_$format
         
-        # with the result from xfst/foma, if available..
-        if ! [ "$example" = "FinnishNumerals" -o \
-            "$example" = "FinnishProsody" -o \
-            "$example" = "Palindromes" ]; then
-            # special case 1
-            if [ "$example" = "EinsteinsPuzzle" ]; then
-                if ! ($tooldir/hfst-fst2strings --xfst=print-space Result_from_xfst | grep "German coffee Prince fish" > /dev/null); then
+        # special case 1
+        if [ "$example" = "EinsteinsPuzzle" ]; then
+	    echo '(generating all word forms from xfst result, this can take a while)'
+	    if ! [ "$PYTHON" = "" ]; then
+		if ! (cat Expected_result | $PYTHON fst2strings_space.py $PYTHONPATH | grep "German coffee Prince fish" > /dev/null); then
                     echo "  FAIL: Results differ"
                     if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
-                        exit 1;
+			exit 1;
                     fi
-                fi
-                if ! ($tooldir/hfst-fst2strings Result_from_hfst_script_$format | \
-                      grep "fish" | grep "German coffee Prince fish" > /dev/null); then
+		fi
+	    else
+		if ! ($tooldir/hfst-fst2strings --xfst=print-space Expected_result | grep "German coffee Prince fish" > /dev/null); then
                     echo "  FAIL: Results differ"
                     if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
-                        exit 1;
+			exit 1;
                     fi
-                fi
-                continue
-            fi
-            # special case 2
-            if [ "$example" = "NumbersToNumerals" ]; then
-                if ! [ -d tmpdir ]; then
-                    mkdir tmpdir
-                fi
-                cp Result_from_xfst tmpdir/NumbersToNumerals # needed in FinnishNumerals
-                $tooldir/hfst-fst2strings Result_from_xfst | sort > tmp_xfst
-                $tooldir/hfst-fst2strings Result_from_hfst_script_$format | sort > tmp_hfst
-                if ! (diff tmp_xfst tmp_hfst); then
+		fi
+	    fi
+	    echo '(generating all word forms from hfst result, this can take a while)'
+	    if ! [ "$PYTHON" = "" ]; then
+		if ! (cat Result_from_hfst_script_$format | $PYTHON fst2strings.py $PYTHONPATH | \
+			     grep "fish" | grep "German coffee Prince fish" > /dev/null); then
                     echo "  FAIL: Results differ"
                     if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
-                        exit 1;
+			exit 1;
                     fi
-                fi
-                rm -f tmp_hfst tmp_xfst
-                continue
+		fi
+	    else
+		if ! ($tooldir/hfst-fst2strings Result_from_hfst_script_$format | \
+			     grep "fish" | grep "German coffee Prince fish" > /dev/null); then
+                    echo "  FAIL: Results differ"
+                    if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+			exit 1;
+                    fi
+		fi
+	    fi
+            continue
+        fi
+        # special case 2
+        if [ "$example" = "NumbersToNumerals" ]; then
+            if ! [ -d tmpdir ]; then
+                mkdir tmpdir
             fi
-            if ! ($tooldir/hfst-compare $compare_flags Result_from_xfst Result_from_hfst_script_$format); then
-                echo "  FAIL: Results from xfst and hfst scripts ("$format") differ in test "$example", storing results in files:"
-                echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
-                echo "    log/"$example.result_from_hfst_script_using_backend_format_$format
-                if ! [ -d log ]; then
-                    mkdir log
-                fi
-                cp Result_from_xfst log/$example.result_from_xfst_script_using_xfst_tool
-                cp Result_from_hfst_script_$format log/$example.result_from_hfst_script_using_backend_format_$format
+            cp Expected_result tmpdir/NumbersToNumerals # needed in FinnishNumerals
+	    if ! [ "$PYTHON" = "" ]; then
+		cat Expected_result | $PYTHON fst2strings.py $PYTHONPATH | sort > tmp_xfst
+		cat Result_from_hfst_script_$format | $PYTHON fst2strings.py $PYTHONPATH | sort > tmp_hfst
+	    else
+		$tooldir/hfst-fst2strings Expected_result | sort > tmp_xfst
+		$tooldir/hfst-fst2strings Result_from_hfst_script_$format | sort > tmp_hfst
+	    fi
+            if ! (diff tmp_xfst tmp_hfst); then
+                echo "  FAIL: Results differ"
                 if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
                     exit 1;
                 fi
             fi
-            
-        # or with the result in common format.
-        else
-            # special case
-            if [ "$example" = "FinnishNumerals" -a "$format" = "sfst" ]; then
-                echo "    skipping comparing the results, result from SFST will be big because of epsilon handling in composition.."
-                continue
-            fi
+            rm -f tmp_hfst tmp_xfst
+            continue
+        fi
+	# special case 3
+        if [ "$example" = "FinnishNumerals" -a "$format" = "sfst" ]; then
+            echo "    skipping comparing the results, result from SFST will be big because of epsilon handling in composition.."
+            continue
+        fi
 
-            if ! [ "$format" = "$common_format" ]; then
-                if ! ($tooldir/hfst-compare $compare_flags Result_from_hfst_script_$common_format Result_from_hfst_script_$format); then
-                    echo -n "  FAIL: Results from hfst scripts ("$format" and "$common_format") differ in test "$example
-                    echo ", storing results in files:"
-                    echo "    log/"$example.result_from_hfst_script_using_backend_format_$format
-                    echo "    log/"$example.result_from_hfst_script_using_backend_format_$common_format
-                    if ! [ -d log ]; then
-                        mkdir log
-                    fi
-                    cp Result_from_hfst_script_$common_format log/$example.result_from_hfst_script_using_backend_format_$common_format
-                    cp Result_from_hfst_script_$format log/$example.result_from_hfst_script_using_backend_format_$format
-                    if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
-                        exit 1;
-                    fi
-                fi
+	if ! [ "$PYTHON" = "" ]; then
+	    if ! ($PYTHON compare.py Expected_result Result_from_hfst_script_$format $compare_flags $PYTHONPATH); then
+		echo "  FAIL: Results from xfst and hfst scripts ("$format") differ in test "$example", storing results in files:"
+		echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
+		echo "    log/"$example.result_from_hfst_script_using_backend_format_$format
+		if ! [ -d log ]; then
+                    mkdir log
+		fi
+		cp Expected_result log/$example.result_from_xfst_script_using_xfst_tool
+		cp Result_from_hfst_script_$format log/$example.result_from_hfst_script_using_backend_format_$format
+		if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+                    exit 1;
+		fi
             fi
-        fi
+	else
+            if ! ($tooldir/hfst-compare $compare_flags Expected_result Result_from_hfst_script_$format); then
+		echo "  FAIL: Results from xfst and hfst scripts ("$format") differ in test "$example", storing results in files:"
+		echo "    log/"$example.result_from_xfst_script_using_xfst_tool 
+		echo "    log/"$example.result_from_hfst_script_using_backend_format_$format
+		if ! [ -d log ]; then
+                    mkdir log
+		fi
+		cp Expected_result log/$example.result_from_xfst_script_using_xfst_tool
+		cp Result_from_hfst_script_$format log/$example.result_from_hfst_script_using_backend_format_$format
+		if [ "$EXIT_IF_NOT_EQUIVALENT" = "true" ]; then
+                    exit 1;
+		fi
+            fi
+	fi
     done
     fi
 
 done
 
-rm -f Result_from_xfst Result
+rm -f Expected_result Result
 for format in $backend_formats;
 do 
     rm -f Result_from_hfst_script_$format
 done
 
 rm -f tmpdir/NumbersToNumerals
-rmdir tmpdir
+if [ -d "tmpdir" ]; then
+    rmdir tmpdir
+fi
 
 echo ""
 echo "**********"
 echo "All fsmbook tests that were performed passed."
-#echo "Returning a skip value because result from DateParser test is compared with result from foma"
-#echo "instead of xfst, because foma and xfst handle symbols that are enclosed in square brackets"
-#echo "differently."
 echo "**********"
 echo ""
-#exit 77
+
diff --git a/test/tools/pmatch-functionality.sh b/test/tools/pmatch-functionality.sh
index 039f19f..86cfd91 100755
--- a/test/tools/pmatch-functionality.sh
+++ b/test/tools/pmatch-functionality.sh
@@ -24,9 +24,7 @@ if ! $srcdir/pmatch-tests.sh --log none; then
     if [ -e $srcdir/pmatch-tests.sh.* ]; then
         rm $srcdir/pmatch-tests.sh.*
     fi
-    exit 77
-    # Pending stabilisation of various things the suite fails, so we pretend
-    # we skipped it
+    exit 1
 fi
 
 if [ -e $srcdir/pmatch-tests.sh.* ]; then
diff --git a/test/tools/pmatch-tests.sh b/test/tools/pmatch-tests.sh
index 1d067eb..8b7fbc0 100755
--- a/test/tools/pmatch-tests.sh
+++ b/test/tools/pmatch-tests.sh
@@ -8,20 +8,6 @@ fi
 
 . $srcdir/pmatch-tester.sh
 
-# Tests that currently fail are skipped.
-# The last three tests pass in some environments.
-exclude_tests="(Converting tags with replacement)\
-|(Replace semantics)\
-|(Add characters with replacement or transduction)\
-|(Transductions and replacements with EndTag)\
-|(OptCap, ToUpper, ToLower)\
-|(Named expressions in OptCap, ToUpper)\
-|(Long input lines)\
-|(Any character except in a set)\
-|(Referring to a double quote in a regexp)\
-|(Character literal escapes)\
-|(Named expressions in replace)"
-
 testset_begin "Testing Pmatch"
 
 set_runner_opts -n
@@ -51,7 +37,7 @@ Define TOP "foo";'
 # Bug/feature (reported 2013-01-22)
 
 check_compile_run 'Define name containing a 0' \
-    'Define T0 [Alpha+ EndTag(A)]; Define TOP T0;' \
+    'set need-separators off Define T0 [Alpha+ EndTag(A)]; Define TOP T0;' \
     '0abc1' '0<A>abc</A>1'
 
 
@@ -69,41 +55,31 @@ done
 test_begin 'Semicolons'
 
 check_compile_run \
-    --codetempl 'Define TOP @1@ EndTag(X);' \
+    --codetempl 'set need-separators off Define TOP @1@ EndTag(X);' \
     --descrtempl 'Semicolon to be marked: @1@' \
     --templarg-single '[{;}]' '({;})' '{;}' '";"' '%;'\
     --inout '' 'a;b' 'a<X>;</X>b'
 
 
 # Missing feature (reported 2013-01-23)
+# [\Whitespace] works too, but the test script expands the complement symbol \
+# so that part of the test was moved to pmatch2fst-functionality.sh
 
 test_begin "Any character except in a set"
 
 check_compile_run \
     --codetempl 'Define TOP @1@ EndTag(A);' \
     --descrtempl 'Any except Whitespace: @1@' \
-    --templarg-single '[\Whitespace]+' '[? - Whitespace]+' \
+    --templarg-single '[? - Whitespace]+' \
     --inout '' 'ab c  de' '<A>ab</A> <A>c</A>  <A>de</A>'
 
-
-# Bug (reported 2013-01-22)
-
-test_begin "Referring to a double quote in a regexp"
-
-check_compile_run \
-    --codetempl 'Define TOP @1@ EndTag(Q);' \
-    --descrtempl 'Double quote as @1@' \
-    --templarg-single '"\x22"' '"\""' '{"}' '%"' \
-    --inout '' 'a "b" c' 'a <Q>"</Q>b<Q>"</Q> c'
-
-
 # Bug (reported 2013-01-14): RC() required a character between
 # recognized string and context
 
 test_begin "RC() with no character between the recognized string and context"
 
 check_compile_run 'RC() separating space' \
-    'Define TOP {a} RC({b}) EndTag(AB);' 'aba b' '<AB>a</AB>ba b'
+    'set need-separators off Define TOP {a} RC({b}) EndTag(AB);' 'aba b' '<AB>a</AB>ba b'
 
 
 # Bug (reported 2013-05-30): Ins() with a name containing "name" does
@@ -124,7 +100,7 @@ Define TOP [ Ins(@1@) ] ;' \
 test_begin "Different tag in different contexts"
 
 check_compile_run '' \
-    'Define TOP {a} [[RC({b}) EndTag(AB)] | [RC({c}) EndTag(AC)]];' \
+    'set need-separators off Define TOP {a} [[RC({b}) EndTag(AB)] | [RC({c}) EndTag(AC)]];' \
     'ab ac' '<AB>a</AB>b <AC>a</AC>c'
 
 
@@ -162,16 +138,11 @@ in='X <A>y</A>'
 out='<X>X y</X>'
 
 check_compile_run \
-    --codetempl 'Define TOP {X } [{<A>} -> 0] @1 at + [{</A>} -> 0] EndTag(X);' \
+    --codetempl 'Define TOP {X } ([{<A>}:0]) @1 at + ([{</A>}:0]) EndTag(X);' \
     --descrtempl 'Remove tags (@1@)' \
     --templarg-single Alpha LowercaseAlpha \
     --inout '' "$in" "$out"
 
-check_compile_run 'Remove tags only if they exist (Alpha)' \
-    'Define TOP {X } [{<A>} .o. [{<A>} -> 0]] Alpha+ [{</A>} .o. [{</A>} -> 0]] EndTag(X);' \
-    "$in" "$out"
-
-
 # Bug (reported 2013-02-07)
 
 test_begin "Order of contexts and EndTag"
@@ -227,7 +198,7 @@ check_compile_run \
 test_begin "A context as an affix of another"
 
 check_compile_run \
-    --codetempl 'Define T1 [ {c} @1@ EndTag(A) ];
+    --codetempl 'set need-separators off Define T1 [ {c} @1@ EndTag(A) ];
 Define T2 [ {d} LC({b}) EndTag(A) ];
 Define TOP [ T1 | T2 ];' \
     --templargs 'Same context (LC)' 'LC({b})' \
@@ -237,7 +208,7 @@ Define TOP [ T1 | T2 ];' \
 
 check_compile_run \
     --code 'Non-affix contexts' \
-'Define T1 [ {c} LC({a}) EndTag(A) ];
+'set need-separators off Define T1 [ {c} LC({a}) EndTag(A) ];
 Define T2 [ {d} LC({b}) EndTag(A) ];
 Define TOP [ T1 | T2 ];' \
     --inout 'First matches' 'bac' 'ba<A>c</A>' \
@@ -245,7 +216,7 @@ Define TOP [ T1 | T2 ];' \
 
 check_compile_run \
     --code 'Context as a prefix of another (RC)' \
-'Define T1 [ {c} EndTag(A) RC({ba}) ];
+'set need-separators off Define T1 [ {c} EndTag(A) RC({ba}) ];
 Define T2 [ {d} EndTag(A) RC({b}) ];
 Define TOP [ T1 | T2 ];' \
     --inout 'Longer context matches' 'cba' '<A>c</A>ba' \
@@ -257,7 +228,7 @@ Define TOP [ T1 | T2 ];' \
 test_begin "Fix of a bug causing segmentation faults"
 
 check_compile_run \
-    --code 'No errors' 'Define TOP {a} EndTag(A);' \
+    --code 'No errors' 'set need-separators off Define TOP {a} EndTag(A);' \
     --inout 'Single character (ok)' 'a' '<A>a</A>' \
     --inout 'Two characters, single match (ok)' 'ab' '<A>a</A>b'
 
@@ -276,9 +247,13 @@ check_compile_run \
 # This is probably an instance of the bug "adding characters with
 # replacement" below.
 
+# Replacing epsilons doesn't work the way this test expected, so most
+# of the replace rules were changed to string pairs by me, Sam Hardwick,
+# on 2017-08-25.
+
 test_begin "Converting tags with replacement"
 
-code_preamble='Define AlphaToUpper
+code_preamble='set need-separators off Define AlphaToUpper
     ["a":"A" | "b":"B" | "c":"C" | "d":"D" | "e":"E" | "f":"F" | "g":"G" |
      "h":"H" | "i":"I" | "j":"J" | "k":"K" | "l":"L" | "m":"M" | "n":"N" |
      "o":"O" | "p":"P" | "q":"Q" | "r":"R" | "s":"S" | "t":"T" | "u":"U" |
@@ -286,9 +261,9 @@ code_preamble='Define AlphaToUpper
 Define AlphaToUpper3 [AlphaToUpper AlphaToUpper AlphaToUpper] ;
 Define MainTagName [{ENAMEX} | {NUMEX} | {TIMEX}] ;
 Define ConvertStartTag [{<} MainTagName
-			 [[] -> { TYPE=" }] AlphaToUpper3
-			 [[] -> {" SBT="}] AlphaToUpper3
-			 [[] -> {"}] {>}] ;
+			 [0:{ TYPE="}] AlphaToUpper3
+			 [0:{" SBT="}] AlphaToUpper3
+			 [0:{"}] {>}] ;
 Define ConvertEndTag [{</} MainTagName [Alpha+ .o. [Alpha+ -> []]] {>}] ;'
 
 in='<ENAMEXPrsHum>Johan</ENAMEXPrsHum>'
@@ -317,13 +292,13 @@ Define TOP [ConvertStartTag | ConvertEndTag] ;" \
 test_begin "Regex^n"
 
 check_compile_run \
-    --code 'Regex^n' 'Define TOP {a}^3 EndTag(A);' \
+    --code 'Regex^n' 'set need-separators off Define TOP {a}^3 EndTag(A);' \
     --inout 'No match' 'a' 'a' \
     --inout 'One match' 'aaa' '<A>aaa</A>' \
     --inout 'Two matches' 'aaaaaa' '<A>aaa</A><A>aaa</A>'
 
 check_compile_run \
-    --codetempl 'Define TOP {a}@1@ EndTag(A);' \
+    --codetempl 'set need-separators off Define TOP {a}@1@ EndTag(A);' \
     --descrtempl '@1@' \
     --templarg-single '^2,4' '^{2,4}' \
     --inout 'No match' 'a' 'a' \
@@ -334,37 +309,23 @@ check_compile_run \
     --inout 'Two matches' 'aaaaaa' '<A>aaaa</A><A>aa</A>'
 
 check_compile_run \
-    --code 'Regex^<n' 'Define TOP {a}^<3 EndTag(A);' \
+    --code 'Regex^<n' 'set need-separators off Define TOP {a}^<3 EndTag(A);' \
     --inout 'One match 1' 'a' '<A>a</A>' \
     --inout 'One match 2' 'aa' '<A>aa</A>' \
     --inout 'Two matches' 'aaa' '<A>aa</A><A>a</A>' \
 
 check_compile_run \
-    --code 'Regex^>n' 'Define TOP {a}^>3 EndTag(A);' \
+    --code 'Regex^>n' 'set need-separators off Define TOP {a}^>3 EndTag(A);' \
     --inout 'No match 3' 'aaa' 'aaa' \
     --inout 'Match 4' 'aaaa' '<A>aaaa</A>' \
     --inout 'Match 5' 'aaaaa' '<A>aaaaa</A>'
 
 
 # Bug (reported 2013-02-12)
+# Character literal escaping
 
-test_begin "Character literal escapes"
-
-# Unicode escapes \uHHHH and octal escapes \0OOO not implemented in
-# Pmatch
-
-check_compile_run \
-    --codetempl 'Define TOP [@1@ EndTag(A)];' \
-    --descrtempl 'Matching @1@' \
-    --templarg-single '"\x65"' \
-    --inout '' 'ABCDEabcde' 'ABCDEabcd<A>e</A>'
-
-check_compile_run \
-    --codetempl 'Define TOP [{a} -> @1@];' \
-    --descrtempl 'Replacement @1@' \
-    --templarg-single '"\x65"' \
-    --inout '' 'a' 'e'
-
+# this test was moved to pmatch2fst-functionality.sh due
+# to escaping problems in this script's clever tricks
 
 # Bug (reported 2014-10-03) and features
 
@@ -378,7 +339,7 @@ test_begin "Backslash in string literals"
 # and add an explicit trailing newline (\n) to the expected output.
 check_compile_run \
     --printf \
-    --codetempl 'Define TOP [{@1@} EndTag(A)];' \
+    --codetempl 'set need-separators off Define TOP [{@1@} EndTag(A)];' \
     --input '\t\\t\\x65\\}' \
     --outtemplargs 'Backslash escapes }' '\t\\t\\x65\\<A>}</A>\n' '\\}' \
     --outtemplargs 'Literal backslash: @1@' '\t<A>\\t</A>\\x65\\}\n' '\\t' \
@@ -401,85 +362,92 @@ check_compile_run \
 
 
 # Bug/feature (reported 2013-02-22)
+# In 'Rightmost longest replacement ->@', the test apparently expects
+# the result to be only X, but according to hfst-xfst and foma both
+# aX and X result, and hfst-pmatch happens to produce aX (and X, but that gets
+# bumped off). So we don't test that for now.
 
 test_begin "Replace semantics"
 
 check_compile_run \
-    --codetempl 'Define TOP [ [{a}+ {b}+] @1@ {X} ];' \
+    --codetempl 'set need-separators off Define TOP [ [{a}+ {b}+] @1@ {X} ];' \
     --input 'aabb' \
     --outtemplargs 'Bare replacement ->' 'Xb' '->' \
     --outtemplargs 'Leftmost longest replacement @->' 'X' '@->' \
     --outtemplargs 'Leftmost shortest replacement @>' 'Xb' '@>' \
-    --outtemplargs 'Rightmost longest replacement ->@' 'X' '->@' \
     --outtemplargs 'Rightmost shortest replacement >@' 'aX' '>@'
-
+#    --outtemplargs 'Rightmost longest replacement ->@' 'X' '->@' \
 
 # Bug (reported 2013-02-22)
 
+# Again, replacing epsilons or dotted brackets is tricky, I couldn't
+# get these work with other tools either... Needs to be revisited FIXME?
+# Sam Hardwick 2017-08-25
+
 test_begin "Add characters with replacement or transduction"
 
-check_compile_run \
-    --codetempl 'Define TOP [ {<} Alpha+ [@1@ -> {>}] ] ;' \
-    --descrtempl 'Replacing @1@' \
-    --templarg-single '""' '[..]' \
-    --inout 'Non-match' '<1' '<1' \
-    --inout 'One Alpha' '<a' '<a>' \
-    --inout 'Two Alphas' '<aa' '<aa>' \
-    --inout 'Three consecutive Alphas' '<aaa' '<aaa>' \
-    --inout 'Three separate occurrences' '<aa b <aa' '<aa> <b> <aa>' \
-    --inout 'Occurrences separated by a colon' '<aa:<aa' '<aa>:<aa>' \
-    --inout 'Consecutive occurrences' '<aaa<aaa<aaa' '<aaa><aaa><aaa>'
-
-check_compile_run \
-    --codetempl 'Define TOP [ {<} Alpha+ [@1@ -> {>}] {::} ] ;' \
-    --descrtempl 'Replacing @1@, characters after replacement' \
-    --templarg-single '""' '[..]' \
-    --inout 'Non-match prefix' '<1::' '<1::' \
-    --inout 'No matching suffix' '<aa' '<aa' \
-    --inout 'One occurrence' '<aa::<aa' '<aa>::<aa' \
-    --inout 'Two occurrences, separated' '<aa:: <aa::' '<aa>:: <aa>::' \
-    --inout 'Two occurrences, consecutive' '<aa::<aa::' '<aa>::<aa>::' \
-    --inout 'Three replacements, consecutive' '<aaa::<aaa::<aaa::' '<aaa>::<aaa>::<aaa>::'
-
-check_compile_run \
-    --codetempl 'Define TOP [{<} Alpha+ @2@ {>}] ;' \
+# check_compile_run \
+#     --codetempl 'set need-separators off Define TOP [ {<} Alpha+ [@1@ -> {>}] ] ;' \
+#     --descrtempl 'Replacing @1@' \
+#     --templarg-single '""' '[..]' \
+#     --inout 'Non-match' '<1' '<1' \
+#     --inout 'One Alpha' '<a' '<a>' \
+#     --inout 'Two Alphas' '<aa' '<aa>' \
+#     --inout 'Three consecutive Alphas' '<aaa' '<aaa>' \
+#     --inout 'Three separate occurrences' '<aa b <aa' '<aa> <b> <aa>' \
+#     --inout 'Occurrences separated by a colon' '<aa:<aa' '<aa>:<aa>' \
+#     --inout 'Consecutive occurrences' '<aaa<aaa<aaa' '<aaa><aaa><aaa>'
+
+# check_compile_run \
+#     --codetempl 'set need-separators off Define TOP [ {<} Alpha+ [@1@ -> {>}] {::} ] ;' \
+#     --descrtempl 'Replacing @1@, characters after replacement' \
+#     --templarg-single '""' '[..]' \
+#     --inout 'Non-match prefix' '<1::' '<1::' \
+#     --inout 'No matching suffix' '<aa' '<aa' \
+#     --inout 'One occurrence' '<aa::<aa' '<aa>::<aa' \
+#     --inout 'Two occurrences, separated' '<aa:: <aa::' '<aa>:: <aa>::' \
+#     --inout 'Two occurrences, consecutive' '<aa::<aa::' '<aa>::<aa>::' \
+#     --inout 'Three replacements, consecutive' '<aaa::<aaa::<aaa::' '<aaa>::<aaa>::<aaa>::'
+
+check_compile_run \
+    --codetempl 'set need-separators off Define TOP [{<} Alpha+ @2@ {>}] ;' \
     --descrtempl 'Single character after replacement, @1@' \
-    --templargs 'replacing ""' '["" -> {x}]' \
-    --templargs 'replacing [..]' '[[..] -> {x}]' \
     --templargs 'transduction from 0' '0:"x"' \
     --inout '' '<AB>B</AB>' '<ABx>B</AB>'
+    # --templargs 'replacing ""' '["" -> {x}]' \
+    # --templargs 'replacing [..]' '[[..] -> {x}]' \
+
 
 check_compile_run \
-    --codetempl 'Define TOP [[{<} Alpha+ @2@ {>}] | [{</} Alpha+ {>}]] ;' \
+    --codetempl 'set need-separators off Define TOP [[{<} Alpha+ @2@ {>}] | [{</} Alpha+ {>}]] ;' \
     --descrtempl 'Single character after replacement, disjunction, @1@' \
-    --templargs 'replacing ""' '["" -> {x}]' \
-    --templargs 'replacing [..]' '[[..] -> {x}]' \
     --templargs 'transduction from 0' '0:"x"' \
     --inout '' '<AB>B</AB>' '<ABx>B</AB>'
+    # --templargs 'replacing ""' '["" -> {x}]' \
+    # --templargs 'replacing [..]' '[[..] -> {x}]' \
+
 
 check_compile_run \
-    --code 'Transduction' 'Define TOP [ {<} Alpha+ 0:">" ] ;' \
+    --code 'Transduction' 'set need-separators off Define TOP [ {<} Alpha+ 0:">" ] ;' \
     --inout 'Non-match' '<1' '<1' \
     --inout 'Single 1-char occurrence' '<a' '<a>' \
     --inout 'Single 3-char occurrence' '<aaa' '<aaa>' \
     --inout 'Two 2-char occurrences' '<aa<aa' '<aa><aa>'
 
 check_compile_run \
-    --code 'Transduction, suffix required' 'Define TOP [ {<} Alpha+ 0:">" {::} ] ;' \
+    --code 'Transduction, suffix required' 'set need-separators off Define TOP [ {<} Alpha+ 0:">" {::} ] ;' \
     --inout 'Non-match prefix' '<1' '<1' \
     --inout 'No matching suffix' '<a' '<a' \
     --inout 'Single 1-char occurrence' '<a::' '<a>::' \
     --inout 'Single 3-char occurrence' '<aaa::' '<aaa>::' \
     --inout 'Two 2-char occurrences' '<aa::<aa::' '<aa>::<aa>::'
 
-
-
 # Bug/feature (reported 2013-02-22)
 
 test_begin "Transductions and replacements with EndTag"
 
 check_compile_run \
-    --codetempl 'Define TOP [ Alpha+ @1@ EndTag(A) ] ;' \
+    --codetempl 'set need-separators off Define TOP [ Alpha+ @1@ EndTag(A) ] ;' \
     --templarg-single 'Transductions' '["1":"X" | "2":"X" | "3":"X"]+' \
     'Composition and replacement' '[Num+ .o. [Num -> {X}]]' \
     --inout 'No match (Alpha)' 'abc' 'abc' \
@@ -491,93 +459,28 @@ check_compile_run \
 
 check_compile_run \
     --code 'Replacement without composition' \
-    'Define TOP [ Alpha+ [Num -> {X}]+ EndTag(A) ] ;' \
+    'set need-separators off Define TOP [ Alpha+ [Num -> {X}]+ EndTag(A) ] ;' \
     --inout 'Non-replacement only' 'abc' '<A>abc</A>' \
     --inout 'Replacement only' '123' '123' \
     --inout 'Single-char replacement' 'abc1' '<A>abcX</A>' \
-    --inout 'Three-char replacment' 'abc123' '<A>abcXXX</A>' \
-    --inout 'Two consecutive matches' 'abc123abc' '<A>abcXXX</A><A>abc</A>'
-
-# CHECK: The following outputs are as Pmatch outputs but are they
-# correct?
-check_compile_run \
-    --codetempl 'Define TOP [ [Num -> {X}]@1@ EndTag(A) ] ;' \
-    --templargs 'Only replacement in EndTag' '' \
-    --templargs 'Only replacement in EndTag, with +' '+' \
-    --inout 'Non-match' 'abc' 'abc' \
-    --inout 'Non-match + three-char match' 'abc123' 'abc<A>XXX</A>' \
-    --inout 'Non-match + single-char match' 'abc1' 'abc<A>X</A>' \
-    --inout 'Single-char match between non-matches' 'abc1abc' 'abc<A>X</A>abc' \
-    --inout 'Three-char match' '123' '<A>XXX</A>'
+    --inout 'Three-char replacment' 'abc123' '<A>abcXXX</A>'
+# This test part is actually incorrect; the replace keeps accepting identities
+# so they belong in the same tag
+#    --inout 'Two consecutive matches' 'abc123abc' '<A>abcXXX</A><A>abc</A>'
 
 
-# Bug/feature (reported 2013-02-22)
+# The following tests all assume that replacing Num with {X} disallows other
+# characters being matched, which is not true
+# check_compile_run \
+#     --codetempl 'set need-separators off Define TOP [ [Num -> {X}]@1@ EndTag(A) ] ;' \
+#     --templargs 'Only replacement in EndTag' '' \
+#     --templargs 'Only replacement in EndTag, with +' '+' \
+#     --inout 'Non-match' 'abc' 'abc' \
+#     --inout 'Non-match + three-char match' 'abc123' 'abc<A>XXX</A>' \
+#     --inout 'Non-match + single-char match' 'abc1' 'abc<A>X</A>' \
+#     --inout 'Single-char match between non-matches' 'abc1abc' 'abc<A>X</A>abc' \
+#     --inout 'Three-char match' '123' '<A>XXX</A>'
 
-test_begin "Transductions and replacements in EndTag context conditions (unsure about expected output)"
-
-check_compile_run \
-    --codetempl 'Define TOP [ Alpha+ LC(@1@) EndTag(A) ] ;' \
-    --templargs 'Composition and replacement in LC, plus outside' \
-    '[Num .o. [Num -> {X}]]+' \
-    --templargs 'Composition and replacement in LC, plus inside' \
-    '[Num+ .o. [Num -> {X}]]' \
-    --templargs 'Composition and transductions in LC, plus outside' \
-    '[Num .o. ["1":"X" | "2":"X" | "3":"X" | "4":"X"]]+' \
-    --templargs 'Composition and transductions in LC, plus inside' \
-    '[Num+ .o. ["1":"X" | "2":"X" | "3":"X" | "4":"X"]]' \
-    --templargs 'Transductions without composition in LC, plus outside' \
-    '["1":"X" | "2":"X" | "3":"X" | "4":"X"]+' \
-    --templargs 'Transductions without composition in LC, no plus' \
-    '["1":"X" | "2":"X" | "3":"X" | "4":"X"]' \
-    --inout 'No context match' 'abc' 'abc' \
-    --inout '1-char context' '1abc' '1<A>abc</A>' \
-    --inout '2-char context' '12abc' '12<A>abc</A>' \
-    --inout '3-char context' '123abc' '123<A>abc</A>' \
-    --inout '4-char context' '1234abc' '1234<A>abc</A>'
-
-check_compile_run \
-    --codetempl 'Define TOP [ Alpha+ LC(@1@) EndTag(A) ] ;' \
-    --templargs 'Replacement without composition in LC, plus outside' \
-    '[Num -> {X}]+' \
-    --templargs 'Replacement without composition in LC, no plus' \
-    '[Num -> {X}]' \
-    --inout 'No context match' 'abc' '<A>abc</A>' \
-    --inout '1-char context' '1abc' '1<A>abc</A>' \
-    --inout '2-char context' '12abc' '12<A>abc</A>' \
-    --inout '3-char context' '123abc' '123<A>abc</A>' \
-    --inout '4-char context' '1234abc' '1234<A>abc</A>'
-
-check_compile_run \
-    --codetempl 'Define TOP [ Alpha+ RC(@1@) EndTag(A) ] ;' \
-    --templargs 'Composition and replacement in RC, plus outside' \
-    '[Num .o. [Num -> {X}]]+' \
-    --templargs 'Composition and replacement in RC, plus inside' \
-    '[Num+ .o. [Num -> {X}]]' \
-    --templargs 'Composition and transductions in RC, plus outside' \
-    '[Num .o. ["1":"X" | "2":"X" | "3":"X" | "4":"X"]]+' \
-    --templargs 'Composition and transductions in RC, plus inside' \
-    '[Num+ .o. ["1":"X" | "2":"X" | "3":"X" | "4":"X"]]' \
-    --templargs 'Transductions without composition in RC, plus outside' \
-    '["1":"X" | "2":"X" | "3":"X" | "4":"X"]+' \
-    --templargs 'Transductions without composition in RC, no plus' \
-    '["1":"X" | "2":"X" | "3":"X" | "4":"X"]' \
-    --inout 'No context match' 'abc' 'abc' \
-    --inout '1-char context' 'abc1' '<A>abc</A>1' \
-    --inout '2-char context' 'abc12' '<A>abc</A>12' \
-    --inout '3-char context' 'abc123' '<A>abc</A>123' \
-    --inout '4-char context' 'abc1234' '<A>abc</A>1234'
-
-check_compile_run \
-    --codetempl 'Define TOP [ Alpha+ RC(@1@) EndTag(A) ] ;' \
-    --templargs 'Replacement without composition in RC, plus outside' \
-    '[Num -> {X}]+' \
-    --templargs 'Replacement without composition in RC, no plus' \
-    '[Num -> {X}]' \
-    --inout 'No context match' 'abc' '<A>abc</A>' \
-    --inout '1-char context' 'abc1' '<A>abc</A>1' \
-    --inout '2-char context' 'abc12' '<A>abc</A>12' \
-    --inout '3-char context' 'abc123' '<A>abc</A>123' \
-    --inout '4-char context' 'abc1234' '<A>abc</A>1234'
 
 
 # Bug/feature (reported 2013-04-15)
@@ -678,7 +581,7 @@ RC(Whitespace);' \
 test_begin "The last line of input without a trailing newline"
 
 check_compile_run \
-    --code '' 'Define TOP [ Alpha+ EndTag(A) ];' \
+    --code '' 'set need-separators off Define TOP [ Alpha+ EndTag(A) ];' \
     --inout 'Trailing newline in input' '1abc2' '1<A>abc</A>2' \
     --inout --printf 'No trailing newline in input, match ends before end of line' \
     '1abc2' '1<A>abc</A>2\n' \
@@ -688,37 +591,41 @@ check_compile_run \
 
 # Bug/feature (reported 2013-05-30)
 
-test_begin "OptCap, ToUpper, ToLower"
+test_begin "OptCap, UpCase, DownCase"
 
+# Changed these tests to use separators, more realistic use case
 check_compile_run \
-    --code 'OptCap' 'Define TOP OptCap([{a}|{ä}|{š}| LowercaseAlpha LowercaseAlpha+]) EndTag(A) ;' \
-    --inout 'ASCII' 'aA' '<A>a</A><A>A</A>' \
+    --code 'OptCap' 'Define TOP OptCap([{a}|{ä}|{š}| LowercaseAlpha+]) EndTag(A) ;' \
+    --inout 'ASCII' 'a A' '<A>a</A> <A>A</A>' \
     --inout 'Multi-letter ASCII word' \
-    '.abc.Abc.ABC.' '.<A>abc</A>.<A>Abc</A>.<A>A</A>BC.' \
-    --inout 'Latin 1 non-ASCII' 'äÄ' '<A>ä</A><A>Ä</A>' \
-    --inout 'Non-Latin 1' 'šŠ' '<A>š</A><A>Š</A>' \
+    'abc Abc ABC' '<A>abc</A> <A>Abc</A> ABC' \
+    --inout 'Latin 1 non-ASCII' 'ä Ä' '<A>ä</A> <A>Ä</A>'
+# FIXME not supported yet
+#    --inout 'Non-Latin 1' 'š Š' '<A>š</A> <A>Š</A>' \
 
 check_compile_run \
-    --code 'ToUpper' 'Define TOP ToUpper([{a}|{ä}|{š}| LowercaseAlpha LowercaseAlpha+]) EndTag(A) ;' \
+    --code 'UpCase' 'set need-separators off Define TOP UpCase([{a}|{ä}|{š}| LowercaseAlpha LowercaseAlpha+]) EndTag(A) ;' \
     --inout 'ASCII' 'aA' 'a<A>A</A>' \
     --inout 'Multi-letter ASCII word' \
     '.abc.Abc.ABC.' '.abc.<A>A</A>bc.<A>ABC</A>.' \
     --inout 'Latin 1 non-ASCII' 'äÄ' 'ä<A>Ä</A>' \
-    --inout 'Non-Latin 1' 'šŠ' 'š<A>Š</A>'
+# FIXME not supported yet
+#    --inout 'Non-Latin 1' 'šŠ' 'š<A>Š</A>'
 
 check_compile_run \
-    --code 'ToLower' 'Define TOP ToLower([{A}|{Ä}|{Š}| UppercaseAlpha UppercaseAlpha+]) EndTag(A) ;' \
+    --code 'DownCase' 'set need-separators off Define TOP DownCase([{A}|{Ä}|{Š}| UppercaseAlpha UppercaseAlpha+]) EndTag(A) ;' \
     --inout 'ASCII' 'aA' '<A>a</A>A' \
     --inout 'Multi-letter ASCII word' \
     '.abc.Abc.ABC.' '.<A>abc</A>.A<A>bc</A>.ABC.' \
-    --inout 'Latin 1 non-ASCII' 'äÄ' '<A>ä</A>Ä' \
-    --inout 'Non-Latin 1' 'šŠ' '<A>š</A>Š'
+    --inout 'Latin 1 non-ASCII' 'äÄ' '<A>ä</A>Ä'
+# FIXME not supported yet
+# --inout 'Non-Latin 1' 'šŠ' '<A>š</A>Š'
 
 check_fn_singlechar () {
     fn=$1
     shift
     check_compile_run \
-	--codetempl "Define TOP $fn([@1@]) EndTag(A);" \
+	--codetempl "set need-separators off Define TOP $fn([@1@]) EndTag(A);" \
 	--templargs "$fn uppercase single-char pattern" '{B}' \
 	--templargs "$fn lowercase single-char pattern" '{b}' \
 	--templargs "$fn single LowercaseAlpha" 'LowercaseAlpha' \
@@ -731,7 +638,7 @@ check_fn_multichar () {
     fn=$1
     shift
     check_compile_run \
-	--codetempl "Define TOP $fn([@1@]) EndTag(A);" \
+	--codetempl "set need-separators off Define TOP $fn([@1@]) EndTag(A);" \
 	--templargs "$fn uppercase multi-char pattern" '{BCDE}' \
 	--templargs "$fn lowercase multi-char pattern" '{bcde}' \
 	--templargs "$fn multiple LowercaseAlpha" \
@@ -747,7 +654,7 @@ check_fn_multiword () {
     fn=$1
     shift
     check_compile_run \
-	--codetempl "Define TOP $fn([@1@]) EndTag(A);" \
+	--codetempl "set need-separators off Define TOP $fn([@1@]) EndTag(A);" \
 	--templargs "$fn uppercase multi-word pattern" '{BCDE FGHI}' \
 	--templargs "$fn lowercase multi-word pattern" '{bcde fghi}' \
 	--templargs "$fn mixed-case pattern" '{bCdE fGhI}' \
@@ -759,71 +666,71 @@ check_fn_other () {
     shift
     check_compile_run \
 	--code "$fn other single-char pattern" \
-	"Define TOP $fn({.}) EndTag(A);" \
+	"set need-separators off Define TOP $fn({.}) EndTag(A);" \
 	--inout 'Uppercase input' 'B' 'B' \
 	--inout 'Lowercase input' 'b' 'b' \
 	--inout 'Other input' '.' '<A>.</A>' \
 	"$@"
 }
 
-check_fn_singlechar ToUpper \
+check_fn_singlechar UpCase \
     --inout 'Uppercase input' 'B' '<A>B</A>' \
     --inout 'Lowercase input' 'b' 'b' \
     --inout 'Other input' '+' '+'
 
-check_fn_multichar ToUpper \
+check_fn_multichar UpCase \
     --inout 'Uppercase input' 'BCDE' '<A>BCDE</A>' \
     --inout 'Lowercase input' 'bcde' 'bcde' \
     --inout 'Capitalized input' 'Bcde' 'Bcde' \
     --inout 'Other input' '++' '++'
 
-check_fn_multiword ToUpper \
+check_fn_multiword UpCase \
     --inout 'Uppercase input' 'BCDE FGHI' '<A>BCDE FGHI</A>' \
     --inout 'Lowercase input' 'bcde fghi' 'bcde fghi' \
     --inout 'Capitalized input' 'Bcde Fghi' 'Bcde Fghi' \
     --inout 'Mixed-case input' 'bCdE fGhI' 'bCdE fGhI'
 
-check_fn_singlechar ToLower \
+check_fn_singlechar DownCase \
     --inout 'Uppercase input' 'B' 'B' \
     --inout 'Lowercase input' 'b' '<A>b</A>' \
     --inout 'Other input' '+' '+'
 
-check_fn_multichar ToLower \
+check_fn_multichar DownCase \
     --inout 'Uppercase input' 'BCDE' 'BCDE' \
     --inout 'Lowercase input' 'bcde' '<A>bcde</A>' \
     --inout 'Other input' '++' '++'
 
-check_fn_multiword ToLower \
+check_fn_multiword DownCase \
     --inout 'Uppercase input' 'BCDE FGHI' 'BCDE FGHI' \
     --inout 'Lowercase input' 'bcde fghi' '<A>bcde fghi</A>' \
     --inout 'Capitalized input' 'Bcde Fghi' 'Bcde Fghi' \
     --inout 'Mixed-case input' 'bCdE fGhI' 'bCdE fGhI'
 
-check_fn_other ToUpper
-check_fn_other ToLower
+check_fn_other UpCase
+check_fn_other DownCase
 
 check_compile_run \
-    --codetempl "Define TOP ToLower([@1@]) EndTag(A);" \
+    --codetempl "set need-separators off Define TOP DownCase([@1@]) EndTag(A);" \
     --input 'Bcde' \
-    --outtemplargs "ToLower uppercase multi-char pattern, Capitalized input" 'Bcde' '{BCDE}' \
-    --outtemplargs "ToLower lowercase multi-char pattern, Capitalized input" 'Bcde' '{bcde}' \
-    --outtemplargs "ToLower multiple LowercaseAlpha, Capitalized input" 'B<A>cde</A>' \
+    --outtemplargs "DownCase uppercase multi-char pattern, Capitalized input" 'Bcde' '{BCDE}' \
+    --outtemplargs "DownCase lowercase multi-char pattern, Capitalized input" 'Bcde' '{bcde}' \
+    --outtemplargs "DownCase multiple LowercaseAlpha, Capitalized input" 'B<A>cde</A>' \
     'LowercaseAlpha LowercaseAlpha+' \
-    --outtemplargs "ToLower multiple UppercaseAlpha, Capitalized input" 'B<A>cde</A>' \
+    --outtemplargs "DownCase multiple UppercaseAlpha, Capitalized input" 'B<A>cde</A>' \
     'UppercaseAlpha UppercaseAlpha+' \
-    --outtemplargs "ToLower multiple Alpha, Capitalized input" 'B<A>cde</A>' 'Alpha Alpha+' \
-    --outtemplargs "ToLower capitalized multi-char pattern, Capitalized input" 'Bcde' '{Bcde}' \
-    --outtemplargs "ToLower mixed-case pattern, Capitalized input" 'Bcde' '{bCdE}'
+    --outtemplargs "DownCase multiple Alpha, Capitalized input" 'B<A>cde</A>' 'Alpha Alpha+' \
+    --outtemplargs "DownCase capitalized multi-char pattern, Capitalized input" 'Bcde' '{Bcde}' \
+    --outtemplargs "DownCase mixed-case pattern, Capitalized input" 'Bcde' '{bCdE}'
 
 check_compile_run \
-    --codetempl 'Define TOP @1@([{+}|{+ +}]) EndTag(X);' \
+    --codetempl 'set need-separators off Define TOP @1@([{+}|{+ +}]) EndTag(X);' \
     --descrtempl '@1@ punct pattern' \
-    --templarg-single 'OptCap' 'ToUpper' 'ToLower' \
+    --templarg-single 'OptCap' 'UpCase' 'DownCase' \
     --inout 'Single char' '+' '<X>+</X>' \
     --inout 'Multiple chars' '+ +' '<X>+ +</X>'
 
 check_compile_run \
-    --codetempl "Define TOP OptCap([@1@]) EndTag(A);" \
+    --codetempl "set need-separators off Define TOP OptCap([@1@]) EndTag(A);" \
     --templargs "OptCap lowercase single-char pattern" '{b}' \
     --templargs "OptCap single LowercaseAlpha" 'LowercaseAlpha' \
     --templargs "OptCap single Alpha" 'Alpha' \
@@ -832,17 +739,16 @@ check_compile_run \
     --inout 'Other input' '+' '+'
 
 check_compile_run \
-    --codetempl "Define TOP OptCap([@1@]) EndTag(A);" \
+    --codetempl "set need-separators off Define TOP OptCap([@1@]) EndTag(A);" \
     --templargs "OptCap uppercase single-char pattern" '{B}' \
     --templargs "OptCap single UppercaseAlpha" 'UppercaseAlpha' \
     --inout 'Uppercase input' 'B' '<A>B</A>' \
-    --inout 'Lowercase input' 'b' '<A>b</A>' \
+    --inout 'Lowercase input' 'b' 'b' \
     --inout 'Other input' '+' '+'
 
 check_compile_run \
-    --codetempl "Define TOP OptCap([@1@]) EndTag(A);" \
+    --codetempl "set need-separators off Define TOP OptCap([@1@]) EndTag(A);" \
     --templargs "OptCap lowercase multi-char pattern" '{bcde}' \
-    --templargs "OptCap capitalized multi-char pattern" '{Bcde}' \
     --inout 'Lowercase input' 'bcde' '<A>bcde</A>' \
     --inout 'Capitalized input' 'Bcde' '<A>Bcde</A>' \
     --inout 'Uppercase input' 'BCDE' 'BCDE' \
@@ -851,7 +757,7 @@ check_compile_run \
 
 check_compile_run \
     --code 'OptCap multiple LowercaseAlpha' \
-    "Define TOP OptCap([LowercaseAlpha LowercaseAlpha+]) EndTag(A);" \
+    "set need-separators off Define TOP OptCap([LowercaseAlpha LowercaseAlpha+]) EndTag(A);" \
     --inout 'Lowercase input' 'bcde' '<A>bcde</A>' \
     --inout 'Capitalized input' 'Bcde' '<A>Bcde</A>' \
     --inout 'Uppercase input' 'BCDE' 'BCDE' \
@@ -859,7 +765,7 @@ check_compile_run \
     --inout 'Other input' '++' '++'
 
 check_compile_run \
-    --codetempl 'Define TOP OptCap([@1@]) EndTag(A);' \
+    --codetempl 'set need-separators off Define TOP OptCap([@1@]) EndTag(A);' \
     --templargs "OptCap uppercase multi-char pattern" '{BCDE}' \
     --templargs "OptCap multiple UppercaseAlpha" \
     'UppercaseAlpha UppercaseAlpha+' \
@@ -869,15 +775,15 @@ check_compile_run \
     --inout 'Other input' '++' '++'
 
 check_compile_run \
-    --codetempl 'Define TOP OptCap([@1@]) EndTag(A);' \
+    --codetempl 'set need-separators off Define TOP OptCap([@1@]) EndTag(A);' \
     --input 'bCdE' \
     --outtemplargs "OptCap uppercase multi-char pattern, Mixed-case input" \
     'bCdE' '{BCDE}' \
     --outtemplargs "OptCap multiple UppercaseAlpha, Mixed-case input" \
-    '<A>bC</A><A>dE</A>' 'UppercaseAlpha UppercaseAlpha+'
+    'bCdE' 'UppercaseAlpha UppercaseAlpha+'
 
 check_compile_run \
-    --code "OptCap multiple Alpha" 'Define TOP OptCap([Alpha Alpha+]) EndTag(A);' \
+    --code "OptCap multiple Alpha" 'set need-separators off Define TOP OptCap([Alpha Alpha+]) EndTag(A);' \
     --inout 'Lowercase input' 'bcde' '<A>bcde</A>' \
     --inout 'Capitalized input' 'Bcde' '<A>Bcde</A>' \
     --inout 'Uppercase input' 'BCDE' '<A>BCDE</A>' \
@@ -885,7 +791,7 @@ check_compile_run \
     --inout 'Other input' '++' '++'
 
 check_compile_run \
-    --code 'OptCap mixed case pattern' 'Define TOP OptCap([{bCdE}]) EndTag(A);' \
+    --code 'OptCap mixed case pattern' 'set need-separators off Define TOP OptCap([{bCdE}]) EndTag(A);' \
     --inout 'Uppercase input' 'BCDE' 'BCDE' \
     --inout 'Lowercase input' 'bcde' 'bcde' \
     --inout 'Capitalized input' 'Bcde' 'Bcde' \
@@ -894,7 +800,7 @@ check_compile_run \
 
 check_compile_run \
     --code 'OptCap uppercase multi-word pattern' \
-    'Define TOP OptCap([{BCDE FGHI}]) EndTag(A);' \
+    'set need-separators off Define TOP OptCap([{BCDE FGHI}]) EndTag(A);' \
     --inout 'Uppercase input' 'BCDE FGHI' '<A>BCDE FGHI</A>' \
     --inout 'Lowercase input' 'bcde fghi' 'bcde fghi' \
     --inout 'Capitalized input' 'Bcde Fghi' 'Bcde Fghi' \
@@ -902,7 +808,7 @@ check_compile_run \
 
 check_compile_run \
     --code 'OptCap lowercase multi-word pattern' \
-    'Define TOP OptCap([{bcde fghi}]) EndTag(A);' \
+    'set need-separators off Define TOP OptCap([{bcde fghi}]) EndTag(A);' \
     --inout 'Uppercase input' 'BCDE FGHI' 'BCDE FGHI' \
     --inout 'Lowercase input' 'bcde fghi' '<A>bcde fghi</A>' \
     --inout 'Capitalized input' 'Bcde Fghi' '<A>Bcde Fghi</A>' \
@@ -910,7 +816,7 @@ check_compile_run \
 
 check_compile_run \
     --code 'OptCap capitalized multi-word pattern' \
-    'Define TOP OptCap([{Bcde Fghi}]) EndTag(A);' \
+    'set need-separators off Define TOP OptCap([{Bcde Fghi}]) EndTag(A);' \
     --inout 'Uppercase input' 'BCDE FGHI' 'BCDE FGHI' \
     --inout 'Lowercase input' 'bcde fghi' 'bcde fghi' \
     --inout 'Capitalized input' 'Bcde Fghi' '<A>Bcde Fghi</A>' \
@@ -918,7 +824,7 @@ check_compile_run \
 
 check_compile_run \
     --code 'OptCap mixed-case multi-word pattern' \
-    'Define TOP OptCap([{bCdE fGhI}]) EndTag(A);' \
+    'set need-separators off Define TOP OptCap([{bCdE fGhI}]) EndTag(A);' \
     --inout 'Uppercase input' 'BCDE FGHI' 'BCDE FGHI' \
     --inout 'Lowercase input' 'bcde fghi' 'bcde fghi' \
     --inout 'Capitalized input' 'Bcde Fghi' 'Bcde Fghi' \
@@ -932,7 +838,7 @@ test_begin "Ins maximizing globally"
 check_compile_run \
     --code 'Ins followed by a character contained in Ins expression' \
     'Define A [Alpha+]; Define TOP [Ins(A) {a} EndTag(A)];' \
-    --inout '' 'aa' 'aa'
+    --inout '' 'aa' '<A>aa</A>'
 
 check_compile_run \
     --code 'Ins followed by a character not contained in Ins expression' \
@@ -956,7 +862,7 @@ check_compile_run \
 
 # Bug (reported 2013-09-03)
 
-test_begin "Named expressions in OptCap, ToUpper"
+test_begin "Named expressions in OptCap, UpCase"
 
 check_compile_run \
     --code 'Literals in OptCap' \
@@ -969,12 +875,12 @@ check_compile_run \
     '<A>aa</A> <A>Aa</A> AA <A>bb</A> <A>Bb</A> BB'
 
 check_compile_run \
-    --code 'Literals in ToUpper' \
-    'Define TOP [ ToUpper([{aa} | {bb}]) ] EndTag(A);' \
-    --code 'Named expression in ToUpper' \
-    'Define AB [{aa} | {bb}]; Define TOP [ ToUpper(AB) ] EndTag(A);' \
-    --code 'Named expression and literal in ToUpper' \
-    'Define A [{aa}]; Define TOP [ ToUpper([A | {bb}]) ] EndTag(A);' \
+    --code 'Literals in UpCase' \
+    'Define TOP [ UpCase([{aa} | {bb}]) ] EndTag(A);' \
+    --code 'Named expression in UpCase' \
+    'Define AB [{aa} | {bb}]; Define TOP [ UpCase(AB) ] EndTag(A);' \
+    --code 'Named expression and literal in UpCase' \
+    'Define A [{aa}]; Define TOP [ UpCase([A | {bb}]) ] EndTag(A);' \
     --inout '' 'aa Aa AA bb Bb BB' 'aa Aa <A>AA</A> bb Bb <A>BB</A>'
 
 
@@ -999,23 +905,15 @@ gen_input () {
     perl -e 'print "'$1'" x '$2' . "\n"'
 }
 
-a9999=`gen_input a 9999`
-a10000=`gen_input a 10000`
-a10001=`gen_input a 10001`
-# The exact threshold for causing segfaults seemed to vary
-a58178=`gen_input a 58178`
-a58200=`gen_input a 58200`
+# We only check that the input gets through, not that 100001 characters get
+# tagged. This is because of the 5000 level recursion limit, which is on
+# purpose.
+
 a100001=`gen_input a 100001`
 
 check_compile_run \
-    --code '' 'Define TOP [Alpha+ EndTag(A)];' \
-    --inout '9999 characters' "$a9999" "<A>$a9999</A>" \
-    --inout '10000 characters' "$a10000" "<A>$a10000</A>" \
-    --inout '10001 characters' "$a10001" "<A>$a10001</A>" \
-    --inout '58178 characters' "$a58178" "<A>$a58178</A>" \
-    --inout '58200 characters' "$a58200" "<A>$a58200</A>" \
-    --inout '100001 characters' "$a100001" "<A>$a100001</A>"
-
+    --code '' 'Define TOP [Alpha+];' \
+    --inout '100001 characters' "$a100001" "$a100001"
 
 # Bug (reported 2013-10-21)
 
@@ -1053,3 +951,15 @@ check_compile_run \
     --inout 'Multiple matches' \
     'k c a c b c ka c ak c kak c aa c bb c ab c ba c aba c bab c kakb c' \
     'k c <AB>a c</AB> <AB>b c</AB> <AB>ka c</AB> <AB>ak c</AB> <AB>kak c</AB> <AB>aa c</AB> <AB>bb c</AB> <AB>ab c</AB> <AB>ba c</AB> <AB>aba c</AB> <AB>bab c</AB> <AB>kakb c</AB>'
+
+test_begin "Lst()"
+
+check_compile_run \
+    --code 'Match runs of characters in {a, b, c}' 'set need-separators off regex Lst({abc})+ EndTag(A);' \
+    --inout '' 'aa bb aabqbcc xyaz' '<A>aa</A> <A>bb</A> <A>aab</A>q<A>bcc</A> xy<A>a</A>z'
+
+test_begin "Exc()"
+
+check_compile_run \
+    --code 'Match runs of characters not in {a, b, c}' 'set need-separators off regex Exc({abc})+ EndTag(A);' \
+    --inout '' 'aa bb aabqbcc xyaz' 'aa<A> </A>bb<A> </A>aab<A>q</A>bcc<A> xy</A>a<A>z</A>'
diff --git a/test/tools/pmatch2fst-functionality.sh b/test/tools/pmatch2fst-functionality.sh
index 4e32a41..7adeeb0 100755
--- a/test/tools/pmatch2fst-functionality.sh
+++ b/test/tools/pmatch2fst-functionality.sh
@@ -4,12 +4,48 @@ if [ "$srcdir" = "" ] ; then
     srcdir=. ;
 fi
 
-if ! $TOOLDIR/hfst-pmatch2fst $srcdir/pmatch_blanks.txt > test ; then
-        exit 1
-    fi
+if ! $TOOLDIR/hfst-pmatch2fst $srcdir/pmatch_blanks.txt > test.pmatch ; then
+    exit 1
+fi
 # Test with any old string
-if ! $TOOLDIR/hfst-pmatch test < $srcdir/cat.strings > pmatch.out ; then
-        exit 1
-    fi
-rm -f pmatch.out test
+if ! $TOOLDIR/hfst-pmatch --newline test.pmatch < $srcdir/cat.strings > pmatch.out ; then
+    exit 1
+fi
+
+echo 'set need-separators off regex [\Whitespace]+ EndTag(Q);' | $TOOLDIR/hfst-pmatch2fst > test.pmatch
+
+echo 'a b  c' | $TOOLDIR/hfst-pmatch --newline test.pmatch > pmatch.out
+if ! echo '<Q>a</Q> <Q>b</Q>  <Q>c</Q>' | diff pmatch.out - > /dev/null ; then
+    exit 1
+fi
+
+echo 'set need-separators off regex "\x22" EndTag(Q);' | $TOOLDIR/hfst-pmatch2fst > test.pmatch
+
+echo 'a "b"  c' | $TOOLDIR/hfst-pmatch --newline test.pmatch > pmatch.out
+if ! echo 'a <Q>"</Q>b<Q>"</Q>  c' | diff pmatch.out - > /dev/null ; then
+    exit 1
+fi
+
+echo 'set need-separators off regex "\"" EndTag(Q);' | $TOOLDIR/hfst-pmatch2fst > test.pmatch
+
+echo 'a "b"  c' | $TOOLDIR/hfst-pmatch --newline test.pmatch > pmatch.out
+if ! echo 'a <Q>"</Q>b<Q>"</Q>  c' | diff pmatch.out - > /dev/null ; then
+    exit 1
+fi
+
+echo 'set need-separators off regex {"} EndTag(Q);' | $TOOLDIR/hfst-pmatch2fst > test.pmatch
+
+echo 'a "b"  c' | $TOOLDIR/hfst-pmatch --newline test.pmatch > pmatch.out
+if ! echo 'a <Q>"</Q>b<Q>"</Q>  c' | diff pmatch.out - > /dev/null ; then
+    exit 1
+fi
+
+echo 'set need-separators off regex %" EndTag(Q);' | $TOOLDIR/hfst-pmatch2fst > test.pmatch
+
+echo 'a "b"  c' | $TOOLDIR/hfst-pmatch --newline test.pmatch > pmatch.out
+if ! echo 'a <Q>"</Q>b<Q>"</Q>  c' | diff pmatch.out - > /dev/null ; then
+    exit 1
+fi
+
+rm -f pmatch.out test.pmatch
 exit 0
diff --git a/test/tools/tokenize-backtrack-out-giella-cg-contiguous.strings b/test/tools/tokenize-backtrack-out-giella-cg-contiguous.strings
index 486271d..5f0f201 100644
--- a/test/tools/tokenize-backtrack-out-giella-cg-contiguous.strings
+++ b/test/tools/tokenize-backtrack-out-giella-cg-contiguous.strings
@@ -1,9 +1,9 @@
 "<su.>"
-	"." PUNCT <W:0> "<.>"
-		"su" Adv Abbr <W:0> "<su>"
+	"." PUNCT <W:0.0000000000> "<.>"
+		"su" Adv Abbr <W:0.0000000000> "<su>"
 	"." PUNCT <W:0> "<.>"
 		"su" Prn <W:0> "<su>"
 : 
 "<su>"
-	"su" Prn <W:0>
+	"su" Prn <W:0.0000000000>
 :\n
diff --git a/test/tools/tokenize-backtrack-out-giella-cg-spaces.strings b/test/tools/tokenize-backtrack-out-giella-cg-spaces.strings
index 75ed25d..5c09c42 100644
--- a/test/tools/tokenize-backtrack-out-giella-cg-spaces.strings
+++ b/test/tools/tokenize-backtrack-out-giella-cg-spaces.strings
@@ -1,5 +1,5 @@
 "<njeallje   logi guokte>"
-	"njealljelogiguokte" Num ErrSpace <W:0>
+	"njealljelogiguokte" Num ErrSpace <W:0.0000000000>
 	"guokte" Num <W:0> "<guokte>"
 		"logi" Num <W:0> "<  logi >"
 			"njeallje" Num <W:0> "<njeallje >"
diff --git a/test/tools/tokenize-backtrack-out-giella-cg.strings b/test/tools/tokenize-backtrack-out-giella-cg.strings
index df34e77..182c3f2 100644
--- a/test/tools/tokenize-backtrack-out-giella-cg.strings
+++ b/test/tools/tokenize-backtrack-out-giella-cg.strings
@@ -1,21 +1,21 @@
 "<busse>"
-	"busse" N <W:0>
-	"busset" V <W:0>
+	"busse" N <W:0.0000000000>
+	"busset" V <W:0.0000000000>
 : 
 "<skuvla>"
-	"skuvla" N <W:0>
+	"skuvla" N <W:0.0000000000>
 : 
 "<skuvla busse>"
-	"skuvlabusse" N ErrSpace <W:0>
+	"skuvlabusse" N ErrSpace <W:0.0000000000>
 	"busset" V <W:0> "<busse>"
 		"skuvla" N <W:0> "<skuvla >"
 	"busse" N <W:0> "<busse>"
 		"skuvla" N <W:0> "<skuvla >"
 : 
 "<Jan.>"
-	"Jan." N Abbr <W:0>
-	"." PUNCT <W:0> "<.>"
-		"Jan." N Abbr <W:0> "<Jan>"
+	"Jan." N Abbr <W:0.0000000000>
+	"." PUNCT <W:0.0000000000> "<.>"
+		"Jan." N Abbr <W:0.0000000000> "<Jan>"
 	"." PUNCT <W:0> "<.>"
 		"Jan" N Prop <W:0> "<Jan>"
 :\n
diff --git a/test/tools/tokenize-backtrack.lexc b/test/tools/tokenize-backtrack.lexc
index 623a7d9..5532c7e 100644
--- a/test/tools/tokenize-backtrack.lexc
+++ b/test/tools/tokenize-backtrack.lexc
@@ -1,47 +1,47 @@
 Multichar_Symbols
 
-+N
-+Prop
-+V
-+Abbr
-+PUNCT
+% N
+% Prop
+% V
+% Abbr
+% PUNCT
 @PMATCH_INPUT_MARK@
 @PMATCH_BACKTRACK@
-+ErrSpace
+% ErrSpace
 %#
-+Adv
-+Num
-+Prn
-+Cmp
+% Adv
+% Num
+% Prn
+% Cmp
 
 LEXICON Root
 
-skuvla+N:skuvla #;
-busse+N:busse #;
-busset+V:busse #;
-< {skuvla} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " {busse} "+N":0 "+ErrSpace":0 > # ;
+skuvla% N:skuvla #;
+busse% N:busse #;
+busset% V:busse #;
+< {skuvla} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " {busse} " N":0 " ErrSpace":0 > # ;
 
-logi+Num:logi #;
-guokte+Num:guokte #;
-njeallje+Num:njeallje #;
-lo+Cmp#:lo GI;
-lo+Num:lo UNSPACEGI;
+logi% Num:logi #;
+guokte% Num:guokte #;
+njeallje% Num:njeallje #;
+lo% Cmp#:lo GI;
+lo% Num:lo UNSPACEGI;
 ! Silly example, but just to test that spaces on both sides work, as well as multiple backtracking points:
-< {njeallje} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " 0:" " 0:" " {logi} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " {guokte} "+Num":0 "+ErrSpace":0 > # ;
+< {njeallje} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " 0:" " 0:" " {logi} "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":" " {guokte} " Num":0 " ErrSpace":0 > # ;
 
-Jan+N+Prop:Jan #;
-.+PUNCT:. #;
+Jan% N% Prop:Jan #;
+.% PUNCT:. #;
 Jan DOTABBR;
 
-su+Prn:su #;
-su+Adv+Abbr:su DOTNOTAG;
+su% Prn:su #;
+su% Adv% Abbr:su DOTNOTAG;
 
 
 LEXICON DOTABBR
 ! This one should create a new backtrack-point before the dot, but *no* sub-reading:
-< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.}   "+N":0 "+Abbr":0 > # ;
+< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.}   " N":0 " Abbr":0 > # ;
 ! This one should create a new backtrack-point before the dot, *as well as* a sub-reading:
-< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.}:0 "+N":0 "+Abbr":0 "@PMATCH_INPUT_MARK@":0 {.} "+PUNCT":0 > # ;
+< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.}:0 " N":0 " Abbr":0 "@PMATCH_INPUT_MARK@":0 {.} " PUNCT":0 > # ;
 
 ! Want:
 !"<Jan.>"
@@ -53,13 +53,13 @@ LEXICON DOTABBR
 
 LEXICON DOTNOTAG
 ! As the sub-reading-line of DOTABBR, but the two input-marks are right next to each other:
-< "@PMATCH_INPUT_MARK@":0 "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.} "+PUNCT":0 > # ;
+< "@PMATCH_INPUT_MARK@":0 "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 {.} " PUNCT":0 > # ;
 ! TODO: This doesn't give the sub-reading, however; should it?
-!< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 "@PMATCH_INPUT_MARK@":0 {.} "+PUNCT":0 > # ;
+!< "@PMATCH_BACKTRACK@":0 "@PMATCH_INPUT_MARK@":0 "@PMATCH_INPUT_MARK@":0 {.} " PUNCT":0 > # ;
 
 
 LEXICON UNSPACEGI
 @PMATCH_INPUT_MARK@:0 GI;
 
 LEXICON GI
-gi+N:gi #;
+gi% N:gi #;
diff --git a/test/tools/tokenize-dog-in.lexc b/test/tools/tokenize-dog-in.lexc
index a68a368..82f2097 100644
--- a/test/tools/tokenize-dog-in.lexc
+++ b/test/tools/tokenize-dog-in.lexc
@@ -1,29 +1,29 @@
 Multichar_Symbols
 
-+N
-+V
-+Foc
-+Cmp
+% N
+% V
+% Foc
+% Cmp
 @PMATCH_INPUT_MARK@
-+Du3
-+Sg3
-+ErrSpace
+% Du3
+% Sg3
+% ErrSpace
 %#
 
 LEXICON Root
 DOG;
-cat+N+Cmp%#:cat DOG;
-be+V:be SPACEDOG;
-leat+V+Du3:lea UNSPACEDOG;
-leat+V+Sg3:leaba ENDLEX;
-bedog+V:be% dog ENDLEX;
+cat% N% Cmp%#:cat DOG;
+be% V:be SPACEDOG;
+leat% V% Du3:lea UNSPACEDOG;
+leat% V% Sg3:leaba ENDLEX;
+bedog% V:be% dog ENDLEX;
 
 LEXICON ENDLEX
 #;
 
 LEXICON DOG
-dog+N:dog ENDLEX;
-ba+Foc:ba ENDLEX;
+dog% N:dog ENDLEX;
+ba% Foc:ba ENDLEX;
 
 LEXICON SPACEDOG
 @PMATCH_INPUT_MARK@:%  DOG;
diff --git a/test/tools/tokenize-dog-out-cg.strings b/test/tools/tokenize-dog-out-cg.strings
index 72e4d4e..7c1f7fc 100644
--- a/test/tools/tokenize-dog-out-cg.strings
+++ b/test/tools/tokenize-dog-out-cg.strings
@@ -2,12 +2,12 @@
 	
 
 "<dog>"
-	"dog"+N
+	"dog" N
 
 "<be dog>"
-	be+Vdog+N
-	bedog+V
+	be Vdog N
+	bedog V
 
 "<catdog>"
-	cat+N+Cmp#dog+N
+	cat N Cmp#dog N
 
diff --git a/test/tools/tokenize-dog-out-giella-cg-flushing.strings b/test/tools/tokenize-dog-out-giella-cg-flushing.strings
index 4bac074..2af5d94 100644
--- a/test/tools/tokenize-dog-out-giella-cg-flushing.strings
+++ b/test/tools/tokenize-dog-out-giella-cg-flushing.strings
@@ -1,5 +1,5 @@
 "<dog>"
-	"dog" N <W:0>
+	"dog" N <W:0.0000000000>
 :[\\n<\\>]
 "<cat>"
 	"cat" ?
diff --git a/test/tools/tokenize-dog-out-giella-cg-superblank.strings b/test/tools/tokenize-dog-out-giella-cg-superblank.strings
index 7358c0e..4293471 100644
--- a/test/tools/tokenize-dog-out-giella-cg-superblank.strings
+++ b/test/tools/tokenize-dog-out-giella-cg-superblank.strings
@@ -1,5 +1,5 @@
 "<dog>"
-	"dog" N <W:0>
+	"dog" N <W:0.0000000000>
 :[\\n<\\>]
 "<cat>"
 	"cat" ?
diff --git a/test/tools/tokenize-dog-out-giella-cg.strings b/test/tools/tokenize-dog-out-giella-cg.strings
index d10de62..9b8189e 100644
--- a/test/tools/tokenize-dog-out-giella-cg.strings
+++ b/test/tools/tokenize-dog-out-giella-cg.strings
@@ -2,14 +2,14 @@
 	"test" ?
 : 
 "<dog>"
-	"dog" N <W:0>
+	"dog" N <W:0.0000000000>
 : 
 "<be dog>"
-	"dog" N <W:0> "<dog>"
-		"be" V <W:0> "<be >"
-	"bedog" V <W:0>
+	"dog" N <W:0.0000000000> "<dog>"
+		"be" V <W:0.0000000000> "<be >"
+	"bedog" V <W:0.0000000000>
 : 
 "<catdog>"
-	"dog" N <W:0>
-		"cat" N Cmp <W:0>
+	"dog" N <W:0.0000000000>
+		"cat" N Cmp <W:0.0000000000>
 : собака\n
diff --git a/test/tools/tokenize-dog-out-xerox.strings b/test/tools/tokenize-dog-out-xerox.strings
index 21e2485..e839a94 100644
--- a/test/tools/tokenize-dog-out-xerox.strings
+++ b/test/tools/tokenize-dog-out-xerox.strings
@@ -1,9 +1,9 @@
 test	
 
-dog	dog+N
+dog	dog N
 
-be dog	be+Vdog+N
-be dog	bedog+V
+be dog	be Vdog N
+be dog	bedog V
 
-catdog	cat+N+Cmp#dog+N
+catdog	cat N Cmp#dog N
 
diff --git a/tools/src/hfst-optimized-lookup.cc b/tools/src/hfst-optimized-lookup.cc
index 3b1758f..69d4dfa 100644
--- a/tools/src/hfst-optimized-lookup.cc
+++ b/tools/src/hfst-optimized-lookup.cc
@@ -308,7 +308,7 @@ void TransducerHeader::skip_hfst3_header(FILE * f)
         if (type_field != std::string::npos) {
             if (header_tail.find("HFST_OL") != type_field + 5 &&
                 header_tail.find("HFST_OLW") != type_field + 5) {
-                delete headervalue;
+                delete[] headervalue;
                 throw HeaderParsingException();
             }
         }
@@ -526,10 +526,10 @@ void runTransducer (genericTransducer T)
             {
 #ifdef WINDOWS
           if (!pipe_output)
-              hfst_fprintf_console(stdout, "%s\t+?\n\n", str);
+              hfst_fprintf_console(stdout, "%s\t%s\t+?\n\n", str, str);
           else
 #endif
-              std::cout << str << "\t+?" << std::endl << std::endl;
+              std::cout << str << "\t" << str << "\t+?" << std::endl << std::endl;
 
 #ifdef WINDOWS
           if (!pipe_output)
@@ -1090,10 +1090,10 @@ void Transducer::printAnalyses(std::string prepend)
         {
 #ifdef WINDOWS
           if (!pipe_output)
-            hfst_fprintf_console(stdout, "%s\t+?\n\n", prepend.c_str());
+            hfst_fprintf_console(stdout, "%s\t%s\t+?\n\n", prepend.c_str(), prepend.c_str());
           else
 #endif
-          std::cout << prepend << "\t+?" << std::endl << std::endl;
+          std::cout << prepend << "\t" << prepend << "\t+?" << std::endl << std::endl;
 
 #ifdef WINDOWS
           if (!pipe_output)
@@ -1146,10 +1146,10 @@ void TransducerUniq::printAnalyses(std::string prepend)
 
 #ifdef WINDOWS
       if (!pipe_output)
-        hfst_fprintf_console(stdout, "%s\t+?\n\n", prepend.c_str());
+        hfst_fprintf_console(stdout, "%s\t%s\t+?\n\n", prepend.c_str(), prepend.c_str());
       else
 #endif
-        std::cout << prepend << "\t+?" << std::endl << std::endl;
+        std::cout << prepend << "\t" << prepend << "\t+?" << std::endl << std::endl;
 
 #ifdef WINDOWS
       if (!pipe_output)
@@ -1199,10 +1199,10 @@ void TransducerFdUniq::printAnalyses(std::string prepend)
     {
 #ifdef WINDOWS
   if (!pipe_output)
-    hfst_fprintf_console(stdout, "%s\t+?\n\n", prepend.c_str());
+    hfst_fprintf_console(stdout, "%s\t%s\t+?\n\n", prepend.c_str(), prepend.c_str());
   else
 #endif
-      std::cout << prepend << "\t+?" << std::endl << std::endl;
+      std::cout << prepend << "\t" << prepend << "\t+?" << std::endl << std::endl;
 
 #ifdef WINDOWS
   if (!pipe_output)
@@ -1636,10 +1636,10 @@ void TransducerW::printAnalyses(std::string prepend)
     {
 #ifdef WINDOWS
       if (!pipe_output)
-        hfst_fprintf_console(stdout, "%s\t+?\n\n", prepend.c_str());
+        hfst_fprintf_console(stdout, "%s\t%s\t+?\n\n", prepend.c_str(), prepend.c_str());
       else
 #endif
-          std::cout << prepend << "\t+?" << std::endl << std::endl;
+          std::cout << prepend << "\t" << prepend << "\t+?" << std::endl << std::endl;
 
 #ifdef WINDOWS
       if (!pipe_output)
@@ -1715,10 +1715,10 @@ void TransducerWUniq::printAnalyses(std::string prepend)
     {
 #ifdef WINDOWS
       if (!pipe_output)
-        hfst_fprintf_console(stdout, "%s\t+?\n", prepend.c_str());
+        hfst_fprintf_console(stdout, "%s\t%s\t+?\n", prepend.c_str(), prepend.c_str());
       else
 #endif
-        std::cout << prepend << "\t+?" << std::endl;
+        std::cout << prepend << "\t" << prepend << "\t+?" << std::endl;
 
 #ifdef WINDOWS
       if (!pipe_output)
@@ -1797,10 +1797,10 @@ void TransducerWFdUniq::printAnalyses(std::string prepend)
     {
 #ifdef WINDOWS
       if (!pipe_output)
-        hfst_fprintf_console(stdout, "%s\t+?", prepend);
+        hfst_fprintf_console(stdout, "%s\t%s\t+?", prepend, prepend);
       else
 #endif
-        std::cout << prepend << "\t+?" << std::endl;
+        std::cout << prepend << "\t" << prepend << "\t+?" << std::endl;
 
 #ifdef WINDOWS
       if (!pipe_output)
diff --git a/tools/src/hfst-pmatch.cc b/tools/src/hfst-pmatch.cc
index aa5d9cf..60c0976 100644
--- a/tools/src/hfst-pmatch.cc
+++ b/tools/src/hfst-pmatch.cc
@@ -44,6 +44,33 @@ using std::pair;
 #  include <getopt.h>
 #endif
 
+#ifdef HAVE_READLINE
+#include <unistd.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+/* Read a string, and point buffer to it. */
+void libreadline_getline(char ** buffer)
+{
+  /* If the buffer has already been allocated,
+     return the memory to the free pool. */
+  if (*buffer)
+    {
+        free (*buffer);
+        *buffer = (char *)NULL;
+    }
+
+  /* Get a line from the user. */
+  *buffer = readline("");
+
+  /* If the line has any text in it,
+     save it on the history. */
+  if (*buffer && **buffer)
+    add_history (*buffer);
+}
+
+#endif
+
 #include <math.h>
 #include <errno.h>
 
@@ -115,21 +142,29 @@ void match_and_print(hfst_ol::PmatchContainer & container,
 #else
         hfst::hfst_fprintf_console(stdout, "%s", container.match(input_text, time_cutoff).c_str());
 #endif
+        outstream << std::endl;
+        if (blankline_separated) {
+            outstream << std::endl;
+        }
     } else {
         hfst_ol::LocationVectorVector locations = container.locate(input_text, time_cutoff);
+        bool printed_something = false;
         for(hfst_ol::LocationVectorVector::const_iterator it = locations.begin();
             it != locations.end(); ++it) {
             if (it->at(0).output.compare("@_NONMATCHING_@") != 0) {
+                printed_something = true;
 #ifndef _MSC_VER
-              outstream << it->at(0).start << "|" << it->at(0).length << "|"
+                outstream << it->at(0).start << "|" << it->at(0).length << "|"
                           << it->at(0).output << "|" << it->at(0).tag << std::endl;
 #else
               hfst::hfst_fprintf_console(stdout, "%i|%i|%s|%s\n", it->at(0).start, it->at(0).length, it->at(0).output.c_str(), it->at(0).tag.c_str());
 #endif
             }
         }
+        if (printed_something) {
+            outstream << std::endl;
+        }
     }
-    outstream << std::endl;
 }
 
 
@@ -140,20 +175,54 @@ int process_input(hfst_ol::PmatchContainer & container,
     char * line = NULL;
     size_t len = 0;
     while (true) {
-
 #ifndef _MSC_VER
-      if (!(hfst_getline(&line, &len, stdin) > 0))
-        break;
+#ifdef HAVE_READLINE
+        if (isatty(STDIN_FILENO)) {
+            libreadline_getline(&line);
+            if (!line)
+                break;
+        } else {
+            if (!(hfst_getline(&line, &len, stdin) > 0))
+                break;
+        }
 #else
-      std::string linestr("");
-      size_t bufsize = 1000;
-      if (! hfst::get_line_from_console(linestr, bufsize, true /* keep newlines */))
-        break;
-      line = strdup(linestr.c_str());
+        if (!(hfst_getline(&line, &len, stdin) > 0))
+            break;
+#endif
+#else
+        std::string linestr("");
+        size_t bufsize = 1000;
+        if (! hfst::get_line_from_console(linestr, bufsize, true /* keep newlines */))
+            break;
+        line = strdup(linestr.c_str());
 #endif
       
         if (!blankline_separated) {
             // newline separated
+#ifndef _MSC_VER
+#ifdef HAVE_READLINE
+            input_text = line;
+            match_and_print(container, outstream, input_text);
+        } else if (line[0] == '\0' || line[0] == '\n') {
+            match_and_print(container, outstream, input_text);
+            input_text.clear();
+        } else {
+            input_text.append(line);
+            if (isatty(STDIN_FILENO)) {
+                input_text.push_back('\n');
+            }
+        }
+#else
+            input_text = line;
+            match_and_print(container, outstream, input_text);
+        } else if (line[0] == '\n') {
+            match_and_print(container, outstream, input_text);
+            input_text.clear();
+        } else {
+            input_text.append(line);
+        }
+#endif
+#else
             input_text = line;
             match_and_print(container, outstream, input_text);
         } else if (line[0] == '\n') {
@@ -162,10 +231,12 @@ int process_input(hfst_ol::PmatchContainer & container,
         } else {
             input_text.append(line);
         }
+#endif
+
         free(line);
         line = NULL;
     }
-    
+
     if (blankline_separated && !input_text.empty()) {
         match_and_print(container, outstream, input_text);
     }
@@ -312,6 +383,11 @@ int main(int argc, char ** argv)
     if (retval != EXIT_CONTINUE) {
         return retval;
     }
+#ifdef HAVE_READLINE
+    // Disable tab completion
+    rl_bind_key('\t', rl_insert);
+#endif
+
     std::ifstream instream(inputfilename,
                            std::ifstream::binary);
     if (!instream.good()) {
diff --git a/tools/src/hfst-pmatch2fst.cc b/tools/src/hfst-pmatch2fst.cc
index 089039a..43ef21c 100644
--- a/tools/src/hfst-pmatch2fst.cc
+++ b/tools/src/hfst-pmatch2fst.cc
@@ -77,6 +77,7 @@ static char *epsilonname=NULL;
 static bool disjunct_expressions=false;
 static bool line_separated = false;
 static bool flatten = false;
+static bool include_cosine_distances = false;
 static clock_t timer;
 
 #if HAVE_OPENFST
@@ -100,7 +101,8 @@ print_usage()
     print_common_unary_program_options(message_out);
     fprintf(message_out, "String and format options:\n"
             "  -e, --epsilon=EPS         Map EPS as zero\n"
-            "      --flatten             Compile in all RTNs\n");
+            "      --flatten             Compile in all RTNs\n"
+            "      --cosine-distances    When compiling Like() operations, include cosine distance info\n");
     fprintf(message_out, "\n");
 
     fprintf(message_out,
@@ -133,11 +135,12 @@ parse_options(int argc, char** argv)
                 HFST_GETOPT_UNARY_LONG,
                 {"epsilon", required_argument, 0, 'e'},
                 {"flatten", no_argument, 0, '1'},
+                {"cosine-distances", no_argument, 0, '2'},
                 {0,0,0,0}
             };
         int option_index = 0;
         int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT
-                             HFST_GETOPT_UNARY_SHORT "e:1:",
+                             HFST_GETOPT_UNARY_SHORT "e:",
                              long_options, &option_index);
         if (-1 == c)
         {
@@ -154,6 +157,9 @@ parse_options(int argc, char** argv)
         case '1':
             flatten = true;
             break;
+        case '2':
+            include_cosine_distances = true;
+            break;
 #include "inc/getopt-cases-error.h"
         }
     }
@@ -194,6 +200,7 @@ process_stream(HfstOutputStream& outstream)
     PmatchCompiler comp(compilation_format);
     comp.set_verbose(verbose);
     comp.set_flatten(flatten);
+    comp.set_include_cosine_distances(include_cosine_distances);
     std::string file_contents;
     std::map<std::string, HfstTransducer*> definitions;
     int c;
diff --git a/tools/src/hfst-tagger/src/use_model_src/DataTypes.h b/tools/src/hfst-tagger/src/use_model_src/DataTypes.h
index 57e3a61..07e3210 100644
--- a/tools/src/hfst-tagger/src/use_model_src/DataTypes.h
+++ b/tools/src/hfst-tagger/src/use_model_src/DataTypes.h
@@ -5,12 +5,18 @@
 #  include <config.h>
 #endif
 
-#ifdef USE_TR1_UNORDERED_MAP
+#ifdef INCLUDE_TR1_UNORDERED_MAP_AND_SET
  #include <tr1/unordered_map>
 #else
  #include <unordered_map>
 #endif
 
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
+  using std::tr1::unordered_map;
+#else
+  using std::unordered_map;
+#endif
+
 #include <string>
 #include <vector>
 
@@ -24,33 +30,18 @@ struct TransitionData
   State  target;
 };
 
-#ifdef USE_TR1_UNORDERED_MAP
- typedef std::tr1::unordered_map<std::string,Symbol> Symbol2NumberMap;
-#else
- typedef std::unordered_map<std::string,Symbol> Symbol2NumberMap;
-#endif
 
+typedef unordered_map<std::string,Symbol> Symbol2NumberMap;
 typedef std::vector<std::string>               Number2SymbolMap;
-
 typedef std::vector<Weight> StateFinalWeightMap;
 
-#ifdef USE_TR1_UNORDERED_MAP
- typedef std::tr1::unordered_map<Symbol,TransitionData> Symbol2TransitionDataMap;
-#else
- typedef std::unordered_map<Symbol,TransitionData> Symbol2TransitionDataMap;
-#endif
-
+typedef unordered_map<Symbol,TransitionData> Symbol2TransitionDataMap;
 typedef std::vector<Symbol2TransitionDataMap>     TransitionMap;
 
 typedef std::pair<size_t,Weight> IdWeightPair;
 
-#ifdef USE_TR1_UNORDERED_MAP
- typedef std::tr1::unordered_map<std::string,IdWeightPair> StringWeightMap;
- typedef std::tr1::unordered_map<std::string,float> ProbabilityMap;
-#else
- typedef std::unordered_map<std::string,IdWeightPair> StringWeightMap;
- typedef std::unordered_map<std::string,float> ProbabilityMap;
-#endif
+typedef unordered_map<std::string,IdWeightPair> StringWeightMap;
+typedef unordered_map<std::string,float> ProbabilityMap;
 
 #define DEFAULT_SYMBOL "<NONE>"
 #define DEFAULT 1
diff --git a/tools/src/hfst-tagger/src/use_model_src/NewLexicalModel.h b/tools/src/hfst-tagger/src/use_model_src/NewLexicalModel.h
index be28795..c2164cc 100644
--- a/tools/src/hfst-tagger/src/use_model_src/NewLexicalModel.h
+++ b/tools/src/hfst-tagger/src/use_model_src/NewLexicalModel.h
@@ -7,16 +7,20 @@
 
 #include "HfstTransducer.h"
 
-#ifdef USE_TR1_UNORDERED_MAP
+#ifdef INCLUDE_TR1_UNORDERED_MAP_AND_SET
  #include <tr1/unordered_map>
+ #include <tr1/unordered_set>
 #else
  #include <unordered_map>
+ #include <unordered_set>
 #endif
 
-#ifdef USE_TR1_UNORDERED_SET
- #include <tr1/unordered_set>
+#ifdef USE_TR1_UNORDERED_MAP_AND_SET
+using std::tr1::unordered_map;
+using std::tr1::unordered_set;
 #else
- #include <unordered_set>
+using std::unordered_map;
+using std::unordered_set;
 #endif
 
 #include <iostream>
@@ -41,13 +45,9 @@ class NewLexicalModel
   bool is_oov(const std::string &word);
   bool is_lexicon_oov(const std::string &word);
  private:
-#ifdef USE_TR1_UNORDERED_MAP
-  typedef std::tr1::unordered_map<std::string,WeightedStringVector>
-    AnalysisCache;
-#else
-  typedef std::unordered_map<std::string,WeightedStringVector>
+
+  typedef unordered_map<std::string,WeightedStringVector>
     AnalysisCache;
-#endif
 
   AnalysisCache   analysis_cache;
   AnalysisCache   upper_case_suffix_cache;
@@ -71,13 +71,8 @@ class NewLexicalModel
   size_t id;
   bool lexical_model_is_broken;
   std::istream * paradigm_guess_stream;
-#ifdef USE_TR1_UNORDERED_SET
-  std::tr1::unordered_set<std::string> o_o_v_words;
-  std::tr1::unordered_set<std::string> lexicon_o_o_v_words;
-#else
-  std::unordered_set<std::string> o_o_v_words;
-  std::unordered_set<std::string> lexicon_o_o_v_words;
-#endif
+  unordered_set<std::string> o_o_v_words;
+  unordered_set<std::string> lexicon_o_o_v_words;
 
   void initialize_tag_probabilities(void);
 
diff --git a/tools/src/hfst-tokenize.cc b/tools/src/hfst-tokenize.cc
index 91a0075..7a34ae5 100644
--- a/tools/src/hfst-tokenize.cc
+++ b/tools/src/hfst-tokenize.cc
@@ -24,7 +24,6 @@
 #include <iterator>
 #include <iostream>
 #include <fstream>
-#include <iterator>
 
 #include <vector>
 #include <map>
@@ -46,6 +45,7 @@ using std::pair;
 #include "hfst-program-options.h"
 #include "hfst-tool-metadata.h"
 #include "implementations/optimized-lookup/pmatch.h"
+#include "implementations/optimized-lookup/pmatch_tokenize.h"
 #include "parsers/pmatch_utils.h"
 #include "HfstExceptionDefs.h"
 #include "HfstDataTypes.h"
@@ -57,35 +57,18 @@ using hfst::HfstTransducer;
 #include "inc/globals-common.h"
 #include "inc/globals-unary.h"
 
+using hfst_ol::Location;
+using hfst_ol::LocationVector;
+using hfst_ol::LocationVectorVector;
+using namespace hfst_ol_tokenize;
+
 static bool superblanks = false; // Input is apertium-style superblanks (overrides blankline_separated)
 static bool blankline_separated = true; // Input is separated by blank lines (as opposed to single newlines)
 static bool keep_newlines = false;
-static bool print_all = false;
-static bool print_weights = false;
-static bool tokenize_multichar = false;
-static string tag_separator = "+"; // + and # are hardcoded in cg-conv at least
-static string subreading_separator = "#";
-static string wtag = "W"; // TODO: cg-conv has an argument --wtag, allow changing here as well?
-static double time_cutoff = 0.0;
 static int token_number = 1;
-static int max_weight_classes = std::numeric_limits<int>::max();
-static bool dedupe = false;
 std::string tokenizer_filename;
 static hfst::ImplementationType default_format = hfst::TROPICAL_OPENFST_TYPE;
-enum OutputFormat {
-    tokenize,
-    space_separated,
-    xerox,
-    cg,
-    finnpos,
-    giellacg,
-    conllu
-};
-OutputFormat output_format = tokenize;
-
-using hfst_ol::Location;
-using hfst_ol::LocationVector;
-using hfst_ol::LocationVectorVector;
+TokenizeSettings settings;
 
 void
 print_usage()
@@ -98,10 +81,12 @@ print_usage()
     fprintf(message_out,
             "  -n, --newline            Newline as input separator (default is blank line)\n"
             "  -a, --print-all          Print nonmatching text\n"
-            "  -w, --print-weight       Print weights\n"
+            "  -w, --print-weight       Print weights (overrides earlier -W option)\n"
+            "  -W, --no-weights         Don't print weights (default; overrides earlier -w, or -w implied by -g, options)\n"
             "  -m, --tokenize-multichar Tokenize multicharacter symbols\n"
             "                           (by default only one utf-8 character is tokenized at a time\n"
             "                           regardless of what is present in the alphabet)\n"
+            "  -b, --beam=B             Output only analyses whose weight is within B from\n"
             "  -tS, --time-cutoff=S     Limit search after having used S seconds per input\n"
             "  -lN, --weight-classes=N  Output no more than N best weight classes\n"
             "                           (where analyses with equal weight constitute a class\n"
@@ -111,9 +96,9 @@ print_usage()
             "  -x, --xerox              Xerox output\n"
             "  -c, --cg                 Constraint Grammar output\n"
             "  -S, --superblanks        Ignore contents of unescaped [] (cf. apertium-destxt); flush on NUL\n"
-            "  -g, --giella-cg          CG format used in Giella infrastructe (implies -l2,\n"
+            "  -g, --giella-cg          CG format used in Giella infrastructure (implies -w and -l2,\n"
             "                           treats @PMATCH_INPUT_MARK@ as subreading separator,\n"
-            "                           expects tags to start or end with +, flush on NUL)\n"
+            "                           expects tags to be Multichar_symbols, flush on NUL)\n"
             "  -C  --conllu             CoNLL-U format\n"
             "  -f, --finnpos            FinnPos output\n");
     fprintf(message_out,
@@ -127,51 +112,9 @@ print_usage()
     fprintf(message_out, "\n");
 }
 
-void print_no_output(std::string const & input, std::ostream & outstream)
-{
-    if (output_format == tokenize || output_format == space_separated) {
-        outstream << input;
-    } else if (output_format == xerox) {
-        outstream << input << "\t" << input << "+?";
-    } else if (output_format == cg || output_format == giellacg) {
-	    outstream << "\"<" << input << ">\"" << std::endl << "\t\"" << input << "\" ?";
-    }
-//    std::cerr << "from print_no_output\n";
-    outstream << "\n\n";
-}
 
-void print_escaping_newlines(std::string const & str, std::ostream & outstream)
-{
-    // TODO: inline?
-    size_t i = 0, j = 0;
-    while((j = str.find("\n", i)) != std::string::npos) {
-        outstream << str.substr(i, j-i) << "\\n";
-        i = j+1;
-    }
-    outstream << str.substr(i, j-i);
-}
 
-void print_nonmatching_sequence(std::string const & str, std::ostream & outstream)
-{
-    if (output_format == tokenize || output_format == space_separated) {
-        outstream << str;
-    } else if (output_format == xerox) {
-        outstream << str << "\t" << str << "+?";
-    } else if (output_format == cg) {
-        outstream << "\"<" << str << ">\"" << std::endl << "\t\"" << str << "\" ?";
-    } else if (output_format == giellacg) {
-        outstream << ":";
-        print_escaping_newlines(str, outstream);
-    } else if (output_format == conllu) {
-        outstream << str;
-    } else if (output_format == finnpos) {
-        outstream << str << "\t_\t_\t_\t_";
-    }
-//    std::cerr << "from print_nonmatching_sequence\n";
-    outstream << "\n";
-}
-
-hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
+hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer * dictionary)
 {
     HfstTransducer * word_boundary = hfst::pmatch::PmatchUtilityTransducers::
         make_latin1_whitespace_acceptor(default_format);
@@ -202,10 +145,10 @@ hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
     left_context->concatenate(*left_context_exit);
     right_context->concatenate(*right_context_exit);
     delete left_context_exit; delete right_context_exit;
-    std::string dict_name = dictionary.get_name();
+    std::string dict_name = dictionary->get_name();
     if (dict_name == "") {
         dict_name = "unknown_pmatch_tokenized_dict";
-        dictionary.set_name(dict_name);
+        dictionary->set_name(dict_name);
     }
     HfstTransducer dict_ins_arc(hfst::pmatch::get_Ins_transition(dict_name.c_str()), default_format);
     // We now make the center of the tokenizer
@@ -219,9 +162,9 @@ hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
     tokenizer->set_name("TOP");
     tokenizer->minimize();
     // Convert the dictionary to olw if it wasn't already
-    dictionary.convert(hfst::HFST_OLW_TYPE);
+    dictionary->convert(hfst::HFST_OLW_TYPE);
     // Get the alphabets
-    std::set<std::string> dict_syms = dictionary.get_alphabet();
+    std::set<std::string> dict_syms = dictionary->get_alphabet();
     std::set<std::string> tokenizer_syms = tokenizer->get_alphabet();
     std::vector<std::string> tokenizer_minus_dict;
     // What to add to the dictionary
@@ -230,7 +173,7 @@ hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
                         std::inserter(tokenizer_minus_dict, tokenizer_minus_dict.begin()));
     for (std::vector<std::string>::const_iterator it = tokenizer_minus_dict.begin();
          it != tokenizer_minus_dict.end(); ++it) {
-        dictionary.insert_to_alphabet(*it);
+        dictionary->insert_to_alphabet(*it);
     }
     hfst::HfstBasicTransducer * tokenizer_basic = hfst::implementations::ConversionFunctions::
         hfst_transducer_to_hfst_basic_transducer(*tokenizer);
@@ -238,640 +181,16 @@ hfst_ol::PmatchContainer make_naive_tokenizer(HfstTransducer & dictionary)
         hfst_basic_transducer_to_hfst_ol(tokenizer_basic,
                                          true, // weighted
                                          "", // no special options
-                                         &dictionary); // harmonize with the dictionary
+                                         dictionary); // harmonize with the dictionary
     delete tokenizer_basic;
     hfst_ol::PmatchContainer retval(tokenizer_ol);
     hfst_ol::Transducer * dict_backend = hfst::implementations::ConversionFunctions::
-        hfst_transducer_to_hfst_ol(&dictionary);
+        hfst_transducer_to_hfst_ol(dictionary);
     retval.add_rtn(dict_backend, dict_name);
     delete tokenizer_ol;
     return retval;
 }
 
-bool location_compare(const Location& lhs, const Location& rhs) {
-    if (lhs.weight == rhs.weight) {
-        if(lhs.tag == rhs.tag) {
-            if(lhs.start == rhs.start){
-                if(lhs.length == rhs.length) {
-                    return lhs.output < rhs.output;
-                }
-                else {
-                    return lhs.length < rhs.length;
-                }
-            }
-            else {
-                return lhs.start < rhs.start;
-            }
-        }
-        else {
-            return lhs.tag < rhs.tag;
-        }
-    }
-    else {
-        return lhs.weight < rhs.weight;
-    }
-};
-
-/**
- * Keep only the max_weight_classes best weight classes
- */
-const LocationVector dedupe_locations(LocationVector const & locations) {
-    if(!dedupe) {
-        return locations;
-    }
-    std::set<Location, bool(*)(const Location& lhs, const Location& rhs)> ls(&location_compare);
-    ls.insert(locations.begin(), locations.end());
-    LocationVector uniq;
-    std::copy(ls.begin(), ls.end(), std::back_inserter(uniq));
-    return uniq;
-}
-/**
- * Keep only the max_weight_classes best weight classes
- */
-const LocationVector keep_n_best_weight(LocationVector const & locations)
-{
-    if(locations.size() <= max_weight_classes) {
-        // We know we won't trim anything, no need to copy the vector:
-        return locations;
-    }
-    int classes_found = -1;
-    hfst_ol::Weight last_weight_class = 0.0;
-    LocationVector goodweight;
-    for (LocationVector::const_iterator it = locations.begin();
-         it != locations.end(); ++it) {
-        if(it->output.empty()) {
-            goodweight.push_back(*it);
-            continue;
-        }
-        hfst_ol::Weight current_weight = it->weight;
-        if (classes_found == -1) // we're just starting
-        {
-            classes_found = 1;
-            last_weight_class = current_weight;
-        }
-        else if (last_weight_class != current_weight)
-        {
-            last_weight_class = current_weight;
-            ++classes_found;
-        }
-        if (classes_found > max_weight_classes)
-        {
-            break;
-        }
-        else {
-            goodweight.push_back(*it);
-        }
-    }
-    return goodweight;
-}
-
-/**
- * Return empty string if it wasn't a tag, otherwise the tag without the initial/final +
- */
-const string as_cg_tag(const string & str) {
-    size_t len = str.size();
-    if(len > 1) {
-        if (str.at(0) == '+') {
-            return str.substr(1);
-        }
-        else if(str.at(len - 1) == '+') {
-            return str.substr(0, len - 1);
-        }
-    }
-    return "";
-}
-
-void print_cg_subreading(size_t const & indent,
-                         hfst::StringVector::const_iterator & out_beg,
-                         hfst::StringVector::const_iterator & out_end,
-                         hfst_ol::Weight const & weight,
-                         hfst::StringVector::const_iterator & in_beg,
-                         hfst::StringVector::const_iterator & in_end,
-                         std::ostream & outstream)
-{
-    outstream << string(indent, '\t');
-    bool in_lemma = false;
-    bool want_spc = false;
-    for(hfst::StringVector::const_iterator it = out_beg;
-        it != out_end; ++it) {
-        if(it->compare("@PMATCH_BACKTRACK@") == 0) {
-            continue;
-        }
-        const string & tag = as_cg_tag(*it);
-        if(in_lemma) {
-            if(tag.empty()) {
-                outstream << (*it);
-            }
-            else {
-                in_lemma = false;
-                outstream << "\" " << tag;
-                want_spc = true;
-            }
-        }
-        else {
-            if(want_spc) {
-                outstream << " ";
-            }
-            if(tag.empty()) {
-                in_lemma = true;
-                outstream << "\"" << (*it);
-            }
-            else {
-                outstream << tag;
-                want_spc = true;
-            }
-        }
-    }
-    if(in_lemma) {
-        outstream << "\"";
-    }
-
-    if (print_weights) {
-        outstream << " <" << wtag << ":" << weight << ">";
-    }
-    if (in_beg != in_end) {
-        std::ostringstream form;
-        std::copy(in_beg, in_end, std::ostream_iterator<string>(form, ""));
-        outstream << " \"<" << form.str() << ">\"";
-    }
-    outstream << std::endl;
-}
-
-typedef std::set<size_t> SplitPoints;
-
-pair<SplitPoints, size_t>
-print_reading_giellacg(const Location *loc,
-                       size_t indent,
-                       const bool always_wftag,
-                       std::ostream & outstream)
-{
-    SplitPoints bt_its;
-    if(loc->output.empty()) {
-        return make_pair(bt_its, indent);
-    }
-    typedef hfst::StringVector::const_iterator PartIt;
-    PartIt
-        out_beg = loc->output_symbol_strings.begin(),
-        out_end = loc->output_symbol_strings.end(),
-        in_beg = loc->input_symbol_strings.begin(),
-        in_end = loc->input_symbol_strings.end();
-    if(!always_wftag) {
-        // don't print input wordform tag unless we've seen a subreading/input mark
-        in_beg = in_end;
-    }
-    size_t part = loc->input_parts.size();
-    while(true) {
-        string inpart;
-        bool sub_found = false;
-        size_t out_part = part > 0 ? loc->output_parts.at(part-1) : 0;
-        while(out_part > 0 && loc->output_symbol_strings.at(out_part-1) == "@PMATCH_BACKTRACK@") {
-            bt_its.insert(loc->input_parts.at(part-1));
-            --part;
-            out_part = part > 0 ? loc->output_parts.at(part-1) : 0;
-        }
-        for(PartIt it = out_end-1;
-            it > loc->output_symbol_strings.begin() + out_part;
-            --it) {
-            if(subreading_separator.compare(*it) == 0) {
-                // Found a sub-reading mark
-                out_beg = ++it;
-                sub_found = true;
-                break;
-            }
-        }
-        if(!sub_found) {
-            if(out_part > 0) {
-                // Found an input mark
-                out_beg = loc->output_symbol_strings.begin() + out_part;
-                in_beg = loc->input_symbol_strings.begin() + loc->input_parts.at(part-1);
-                --part;
-            }
-            else {
-                // No remaining sub-marks or input-marks to the left
-                out_beg = loc->output_symbol_strings.begin();
-                if(in_end != loc->input_symbol_strings.end()) {
-                    // We've seen at least one input-mark, so we need to output the remaining input as well
-                    in_beg = loc->input_symbol_strings.begin();
-                }
-            }
-        }
-        print_cg_subreading(indent,
-                            out_beg,
-                            out_end,
-                            loc->weight,
-                            in_beg,
-                            in_end,
-                            outstream);
-        if(out_beg == loc->output_symbol_strings.begin()) {
-            break;
-        }
-        else {
-            ++indent;
-            out_end = out_beg;
-            in_end = in_beg;
-            if(sub_found) {
-                --out_end; // skip the subreading separator symbol
-            }
-        }
-    }
-    if(!bt_its.empty()) {
-        bt_its.insert(0);
-        bt_its.insert(loc->input_symbol_strings.size());
-    }
-    return make_pair(bt_its, indent);
-}
-
-/**
- * Treat syms as "characters" to concatenate and split at indices
- * given by splitpoints to create a new string vector. Assumes
- * splitpoints includes both ends of syms.
- */
-const hfst::StringVector split_at(const hfst::StringVector & syms,
-                                  const SplitPoints * splitpoints)
-{
-    hfst::StringVector subs;
-    if(splitpoints->size() < 2) {
-        std::cerr << "split_at called with " << std::endl;
-        return subs;
-    }
-    // Loop to next-to-last
-    for(SplitPoints::const_iterator it = splitpoints->begin(); std::next(it) != splitpoints->end(); ++it) {
-        std::ostringstream ss;
-        // Copy the substring between this point and the next:
-        std::copy(syms.begin() + *(it),
-                  syms.begin() + *(std::next(it)),
-                  std::ostream_iterator<string>(ss, ""));
-        subs.push_back(ss.str());
-    }
-    return subs;
-}
-
-/*
- * Look up form, filtering out empties and those that don't cover the
- * full string.
- */
-const LocationVector locate_fullmatch(hfst_ol::PmatchContainer & container,
-                                      string & form)
-{
-    LocationVectorVector sublocs = container.locate(form, time_cutoff);
-    LocationVector loc_filtered;
-    // TODO: Worth noticing about? Is this as safe as checking that input.length != form.length?
-    // if(sublocs.size() != 1) {
-    //     std::cerr << "Warning: '" << form << "' only tokenisable by further splitting."<<std::endl;
-    // }
-    for(LocationVectorVector::const_iterator it = sublocs.begin();
-        it != sublocs.end(); ++it) {
-        if (it->empty()
-            || (it->size() == 1 && it->at(0).output.compare("@_NONMATCHING_@") == 0)
-            // keep only those that cover the full form
-            || it->at(0).input.length() != form.length()) {
-            continue;
-        }
-        LocationVector loc = keep_n_best_weight(dedupe_locations(*it));
-        for (LocationVector::const_iterator loc_it = loc.begin();
-             loc_it != loc.end(); ++loc_it) {
-            if(!loc_it->output.empty()
-               && loc_it->weight < std::numeric_limits<float>::max()) {
-                // TODO: why aren't the <W:inf> excluded earlier?
-                loc_filtered.push_back(*loc_it);
-            }
-        }
-    }
-    return loc_filtered;
-}
-
-void print_location_vector_giellacg(hfst_ol::PmatchContainer & container,
-                                    LocationVector const & locations,
-                                    std::ostream & outstream)
-{
-    outstream << "\"<" << locations.at(0).input << ">\"" << std::endl;
-    if(locations.size() == 1 && locations.at(0).output.empty()) {
-        // Treat empty analyses as unknown-but-tokenised:
-        outstream << "\t\"" << locations.at(0).input << "\" ?" << std::endl;
-        return;
-    }
-    // Output regular analyses first, making a note of backtracking points.
-    std::set<SplitPoints> backtrack;
-    for (LocationVector::const_iterator loc_it = locations.begin();
-         loc_it != locations.end(); ++loc_it) {
-        SplitPoints bt_points = print_reading_giellacg(&(*loc_it), 1, false, outstream).first;
-        if(!bt_points.empty()) {
-            backtrack.insert(bt_points);
-        }
-    }
-    if(backtrack.empty()) {
-	return;
-    }
-    // The rest of the function handles possible backtracking:
-    hfst::StringVector in_syms = locations.at(0).input_symbol_strings;
-
-    for(std::set<SplitPoints>::const_iterator bt_points = backtrack.begin();
-        bt_points != backtrack.end(); ++bt_points) {
-
-        // First, for every set of backtrack points, we split on every
-        // point in that N+1-sized set (the backtrack points include
-        // start/end points), and create an N-sized vector splitlocs of
-        // resulting analyses
-        LocationVectorVector splitlocs;
-        hfst::StringVector words = split_at(in_syms, &*(bt_points));
-        for(hfst::StringVector::const_iterator it = words.begin(); it != words.end(); ++it) {
-            // Trim left/right spaces:
-            const size_t first = it->find_first_not_of(' ');
-            const size_t last = it->find_last_not_of(' ') + 1;
-            string form = it->substr(first, last-first);
-            LocationVector loc = locate_fullmatch(container, form);
-            if(loc.size() == 0 && verbose) {
-                std::cerr << "Warning: The analysis of \"<" << locations.at(0).input << ">\" has backtracking around the substring \"<" << form << ">\", but that substring has no analyses." << std::endl;
-                // but push it anyway, since we want exactly one subvector per splitpoint
-            }
-            if(form.length() != it->length()) { // Ensure the spaces we ignored when looking up are output in the form:
-                vector<string> lspace = vector<string>(first, " ");
-                vector<string> rspace = vector<string>(it->length()-last, " ");
-                for(LocationVector::iterator lvit = loc.begin(); lvit != loc.end(); ++lvit) {
-                    lvit->input = form;
-                    vector<string>& syms = lvit->input_symbol_strings;
-                    syms.insert(syms.begin(), lspace.begin(), lspace.end());
-                    syms.insert(syms.end(), rspace.begin(), rspace.end());
-                    for(vector<size_t>::iterator ip = lvit->input_parts.begin(); ip != lvit->input_parts.end(); ++ip) {
-                        *ip += first;
-                    }
-                }
-            }
-            splitlocs.push_back(loc);
-        }
-        if(splitlocs.empty()) {
-            continue;
-        }
-        // Second, we reorder splitlocs so we can output as a
-        // cohort of non-branching CG subreadings; first word as leaf
-        // nodes. This means that splitlocs = [[A,B],[C,D]] should
-        // end up as the sequence
-        // (C,0),(A,1),(C,0),(B,1),(D,0),(A,1),(D,0),(B,1)
-        // (where the number is the initial indentation).
-        size_t depth = 0;
-        const size_t bottom = splitlocs.size()-1;
-        vector<std::ostringstream> out(splitlocs.size());
-        vector<pair<LocationVector, size_t > > stack;
-        // In CG the *last* word is the least indented, so start from
-        // the end of splitlocs, indentation being 1 tab:
-        stack.push_back(make_pair(splitlocs.at(bottom),
-                                  0));
-        while(!stack.empty() && !stack.back().first.empty()) {
-            LocationVector & locs = stack.back().first;
-            const Location loc = locs.back();
-            locs.pop_back();
-            const size_t indent = 1 + stack.back().second;
-            out.at(depth).clear();
-            out.at(depth).str(string());
-            // (ignore splitpoints of splitpoints)
-            const size_t new_indent = print_reading_giellacg(&loc, indent, true, out.at(depth)).second;
-            if(depth == bottom) {
-                for(vector<std::ostringstream>::const_iterator it = out.begin(); it != out.end(); ++it) {
-                    outstream << it->str();
-                }
-            }
-            if(depth < bottom) {
-                ++depth;
-                if(depth > 0) {
-                    stack.push_back(make_pair(splitlocs.at(bottom-depth),
-                                              new_indent));
-                }
-            }
-            else if(locs.empty()) {
-                depth--;
-                stack.pop_back();
-            }
-        }
-    }
-}
-
-// Omorfi-specific at this time
-std::string fetch_and_kill_between(std::string left, std::string right, std::string & analysis)
-{
-    size_t start = analysis.find(left);
-    size_t stop = analysis.find(right, start + 1);
-    if (start == std::string::npos || stop == std::string::npos) {
-        return "";
-    }
-    std::string retval = analysis.substr(start + left.size(), stop - start - left.size());
-    analysis.erase(start, stop - start + right.size());
-    return retval;
-}
-
-std::string fetch_and_kill_feats(std::string & analysis)
-{
-    std::string retval;
-    std::string tmp;
-    tmp = fetch_and_kill_between("[ANIMACY=", "]", analysis);
-    retval += (tmp != "" ? ("Animacy=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[ASPECT=", "]", analysis);
-    retval += (tmp != "" ? ("Aspect=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[CASE=", "]", analysis);
-    retval += (tmp != "" ? ("Case=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[DEFINITE=", "]", analysis);
-    retval += (tmp != "" ? ("Definite=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[CMP=", "]", analysis);
-    retval += (tmp != "" ? ("Degree=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[GENDER=", "]", analysis);
-    retval += (tmp != "" ? ("Gender=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[MOOD=", "]", analysis);
-    retval += (tmp != "" ? ("Mood=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[NEGATIVE=", "]", analysis);
-    retval += (tmp != "" ? ("Negative=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[NUMTYPE=", "]", analysis);
-    retval += (tmp != "" ? ("Numtype=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[NUM=", "]", analysis);
-    retval += (tmp != "" ? ("Number=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[PERS=", "]", analysis);
-    retval += (tmp != "" ? ("Person=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[POSS=", "]", analysis);
-    retval += (tmp != "" ? ("Poss=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[PRONTYPE=", "]", analysis);
-    retval += (tmp != "" ? ("PronType=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[REFLEX=", "]", analysis);
-    retval += (tmp != "" ? ("Reflex=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[TENSE=", "]", analysis);
-    retval += (tmp != "" ? ("Tense=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[VERBFORM=", "]", analysis);
-    retval += (tmp != "" ? ("VerbForm=" + tmp + "|") : "");
-    tmp = fetch_and_kill_between("[VOICE=", "]", analysis);
-    retval += (tmp != "" ? ("Voice=" + tmp + "|") : "");
-    if (retval.size() != 0) {
-        retval.erase(retval.size() - 1);
-    }
-    return retval;
-}
-
-std::string empty_to_underscore(std::string to_test)
-{
-    if (to_test.size() == 0) {
-        return "_";
-    }
-    return to_test;
-}
-
-void print_location_vector(hfst_ol::PmatchContainer & container,
-                           LocationVector const & locations,
-                           std::ostream & outstream)
-{
-    if (output_format == tokenize && locations.size() != 0) {
-        outstream << locations.at(0).input;
-        if (print_weights) {
-            outstream << "\t" << locations.at(0).weight;
-        }
-        outstream << std::endl;
-        if (locations.at(0).tag == "<Boundary=Sentence>") {
-            outstream << std::endl;
-        }
-    } else if (output_format == space_separated && locations.size() != 0) {
-	outstream << locations.at(0).input;
-        if (print_weights) {
-            outstream << "\t" << locations.at(0).weight;
-        }
-        outstream << " ";
-        if (locations.at(0).tag == "<Boundary=Sentence>") {
-            outstream << std::endl;
-        }
-    } else if (output_format == cg && locations.size() != 0) {
-        // Print the cg cohort header
-        outstream << "\"<" << locations.at(0).input << ">\"" << std::endl;
-        for (LocationVector::const_iterator loc_it = locations.begin();
-             loc_it != locations.end(); ++loc_it) {
-            // For the most common case, eg. analysis strings that begin with the original input,
-            // we try to do what cg tools expect and surround the original input with double quotes.
-            // Otherwise we omit the double quotes and assume the rule writer knows what he's doing.
-            if (loc_it->output.find(loc_it->input) == 0) {
-                // The nice case obtains
-                outstream << "\t\"" << loc_it->input << "\"" <<
-                    loc_it->output.substr(loc_it->input.size(), std::string::npos);
-            } else {
-                outstream << "\t" << loc_it->output;
-            }
-            if (print_weights) {
-                outstream << "\t" << loc_it->weight;
-            }
-            outstream << std::endl;
-        }
-        outstream << std::endl;
-    } else if (output_format == giellacg && locations.size() != 0) {
-        print_location_vector_giellacg(container, locations, outstream);
-    } else if (output_format == xerox) {
-        for (LocationVector::const_iterator loc_it = locations.begin();
-             loc_it != locations.end(); ++loc_it) {
-            outstream << loc_it->input << "\t" << loc_it->output;
-            if (print_weights) {
-                outstream << "\t" << loc_it->weight;
-            }
-            outstream << std::endl;
-        }
-        outstream << std::endl;
-    } else if (output_format == conllu) {
-        hfst_ol::Weight lowest_weight = hfst_ol::INFINITE_WEIGHT;
-        hfst_ol::Location best_location;
-        for (LocationVector::const_iterator loc_it = locations.begin();
-             loc_it != locations.end(); ++loc_it) {
-            if (loc_it->weight < lowest_weight) {
-                best_location = *loc_it;
-                lowest_weight = loc_it->weight;
-            }
-//            if (loc_it->tag == "@MULTIWORD@"
-//            outstream << loc_it->input << "\t" << loc_it->output;
-        }
-        outstream << token_number
-                  << "\t" << best_location.input;
-        outstream << "\t" << empty_to_underscore(fetch_and_kill_between("[WORD_ID=", "]", best_location.output));
-        outstream << "\t" << empty_to_underscore(fetch_and_kill_between("[UPOS=", "]", best_location.output));
-        outstream << "\t" << empty_to_underscore(fetch_and_kill_between("[XPOS=", "]", best_location.output));
-        outstream << "\t" << empty_to_underscore(fetch_and_kill_feats(best_location.output))
-                  << "\t" << "_" // HEAD
-                  << "\t" << "_" // DEPREL
-                  << "\t" << "_"; // DEPS
-        outstream << "\t" << empty_to_underscore(best_location.output); // MISC
-                    if (print_weights) {
-                outstream << "\t" << best_location.weight;
-            }
-        outstream << std::endl;
-    } else if (output_format == finnpos) {
-        std::set<std::string> tags;
-        std::set<std::string> lemmas;
-            for (LocationVector::const_iterator loc_it = locations.begin();
-                 loc_it != locations.end(); ++loc_it) {
-                // Assume the last space is where the tags begin
-                size_t tags_start_at = loc_it->output.find_last_of(" ");
-                if (tags_start_at != std::string::npos) {
-                    std::string lemma = loc_it->output.substr(0, tags_start_at);
-                    if (lemma.find_first_of(" ") == std::string::npos) {
-                        // can't have spaces in lemmas
-                        lemmas.insert(lemma);
-                    }
-                    std::string tag = loc_it->output.substr(tags_start_at + 1);
-                    if (tag.find_first_of(" ") == std::string::npos) {
-                        // or tags
-                        tags.insert(tag);
-                    }
-                }
-            }
-        outstream << locations.at(0).input << "\t_\t";
-        // the input and a blank for features
-        if (lemmas.empty()) {
-            outstream << "_";
-        } else {
-            std::string accumulator;
-            for (std::set<std::string>::const_iterator it = lemmas.begin();
-                 it != lemmas.end(); ++it) {
-                accumulator.append(*it);
-                accumulator.append(" ");
-            }
-            outstream << accumulator.substr(0, accumulator.size() - 1);
-        }
-        outstream << "\t";
-        if (tags.empty()) {
-            outstream << "_";
-        } else {
-            std::string accumulator;
-            for (std::set<std::string>::const_iterator it = tags.begin();
-                 it != tags.end(); ++it) {
-                accumulator.append(*it);
-                accumulator.append(" ");
-            }
-            outstream << accumulator.substr(0, accumulator.size() - 1);
-        }
-        outstream << "\t_" << std::endl;
-        if (locations.at(0).tag == "<Boundary=Sentence>") {
-            outstream << std::endl;
-        }
-    }
-//    std::cerr << "from print_location_vector\n";
-}
-
-void match_and_print(hfst_ol::PmatchContainer & container,
-                     std::ostream & outstream,
-                     const string & input_text)
-{
-    LocationVectorVector locations = container.locate(input_text, time_cutoff);
-    if (locations.size() == 0 && print_all) {
-        print_no_output(input_text, outstream);
-    }
-    token_number = 1;
-    for(LocationVectorVector::const_iterator it = locations.begin();
-        it != locations.end(); ++it) {
-        if ((it->size() == 1 && it->at(0).output.compare("@_NONMATCHING_@") == 0)) {
-            if (print_all) {
-                print_nonmatching_sequence(it->at(0).input, outstream);
-            }
-            continue;
-            // All nonmatching cases have been handled
-        }
-        print_location_vector(container,
-                              keep_n_best_weight(dedupe_locations(*it)),
-                              outstream);
-        ++token_number;
-    }
-    if (output_format == finnpos) {
-        outstream << std::endl;
-    }
-}
-
 // TODO: lambda this when C++11 available everywhere
 inline void process_input_0delim_print(hfst_ol::PmatchContainer & container,
                                        std::ostream & outstream,
@@ -879,7 +198,7 @@ inline void process_input_0delim_print(hfst_ol::PmatchContainer & container,
 {
     string input_text(cur.str());
     if(!input_text.empty()) {
-        match_and_print(container, outstream, input_text);
+        match_and_print(container, outstream, input_text, settings);
     }
     cur.clear();
     cur.str(string());
@@ -916,7 +235,7 @@ int process_input_0delim(hfst_ol::PmatchContainer & container,
                 }
                 else {
                     in_blank = false;
-                    print_nonmatching_sequence(cur.str(), outstream);
+                    print_nonmatching_sequence(cur.str(), outstream, settings);
                     cur.clear();
                     cur.str(string());
                 }
@@ -945,7 +264,7 @@ int process_input_0delim(hfst_ol::PmatchContainer & container,
         }
     }
     if(in_blank) {
-        print_nonmatching_sequence(cur.str(), outstream);
+        print_nonmatching_sequence(cur.str(), outstream, settings);
     }
     else {
         process_input_0delim_print(container, outstream, cur);
@@ -964,7 +283,10 @@ inline void maybe_erase_newline(string& input_text)
 int process_input(hfst_ol::PmatchContainer & container,
                   std::ostream & outstream)
 {
-    if(output_format == giellacg || superblanks) {
+    if(settings.output_format == cg || settings.output_format == giellacg) {
+        outstream << std::fixed << std::setprecision(10);
+    }
+    if(settings.output_format == giellacg || superblanks) {
         if(superblanks) {
             return process_input_0delim<true>(container, outstream);
         }
@@ -979,7 +301,7 @@ int process_input(hfst_ol::PmatchContainer & container,
         while (hfst_getline(&line, &bufsize, inputfile) > 0) {
             if (line[0] == '\n') {
                 maybe_erase_newline(input_text);
-                match_and_print(container, outstream, input_text);
+                match_and_print(container, outstream, input_text, settings);
                 input_text.clear();
             } else {
                 input_text.append(line);
@@ -989,7 +311,7 @@ int process_input(hfst_ol::PmatchContainer & container,
         }
         if (!input_text.empty()) {
             maybe_erase_newline(input_text);
-            match_and_print(container, outstream, input_text);
+            match_and_print(container, outstream, input_text, settings);
         }
     }
     else {
@@ -997,7 +319,7 @@ int process_input(hfst_ol::PmatchContainer & container,
         while (hfst_getline(&line, &bufsize, inputfile) > 0) {
             input_text = line;
             maybe_erase_newline(input_text);
-            match_and_print(container, outstream, input_text);
+            match_and_print(container, outstream, input_text, settings);
             free(line);
             line = NULL;
         }
@@ -1019,7 +341,9 @@ int parse_options(int argc, char** argv)
                 {"keep-newline", no_argument, 0, 'k'},
                 {"print-all", no_argument, 0, 'a'},
                 {"print-weights", no_argument, 0, 'w'},
+                {"no-weights", no_argument, 0, 'W'},
                 {"tokenize-multichar", no_argument, 0, 'm'},
+                {"beam", required_argument, 0, 'b'},
                 {"time-cutoff", required_argument, 0, 't'},
                 {"weight-classes", required_argument, 0, 'l'},
                 {"unique", required_argument, 0, 'u'},
@@ -1035,7 +359,7 @@ int parse_options(int argc, char** argv)
                 {0,0,0,0}
             };
         int option_index = 0;
-        int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT "nkawmut:l:zixcSgCf",
+        int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT "nkawWmub:t:l:zixcSgCf",
                              long_options, &option_index);
         if (-1 == c)
         {
@@ -1054,62 +378,74 @@ int parse_options(int argc, char** argv)
             blankline_separated = false;
             break;
         case 'a':
-            print_all = true;
+            settings.print_all = true;
             break;
         case 'w':
-            print_weights = true;
+            settings.print_weights = true;
+            break;
+        case 'W':
+            settings.print_weights = false;
             break;
         case 'm':
-            tokenize_multichar = true;
+            settings.tokenize_multichar = true;
             break;
         case 't':
-            time_cutoff = atof(optarg);
-            if (time_cutoff < 0.0)
+            settings.time_cutoff = atof(optarg);
+            if (settings.time_cutoff < 0.0)
             {
                 std::cerr << "Invalid argument for --time-cutoff\n";
                 return EXIT_FAILURE;
             }
             break;
         case 'u':
-            dedupe = true;
+            settings.dedupe = true;
             break;
+        case 'b':
+          settings.beam = atof(optarg);
+          if (settings.beam < 0)
+          {
+              std::cerr << "Invalid argument for --beam\n";
+              return EXIT_FAILURE;
+          }
+          break;
         case 'l':
-            max_weight_classes = atoi(optarg);
-            if (max_weight_classes < 1)
+            settings.max_weight_classes = atoi(optarg);
+            if (settings.max_weight_classes < 1)
             {
                 std::cerr << "Invalid or no argument --weight-classes count\n";
                 return EXIT_FAILURE;
             }
             break;
         case 'z':
-            output_format = tokenize;
+            settings.output_format = tokenize;
             break;
         case 'i':
-            output_format = space_separated;
+            settings.output_format = space_separated;
             break;
         case 'x':
-            output_format = xerox;
+            settings.output_format = xerox;
             break;
         case 'c':
-            output_format = cg;
+            settings.output_format = cg;
             break;
         case 'C':
-            output_format = conllu;
+            settings.output_format = conllu;
             break;
         case 'S':
             superblanks = true;
             break;
         case 'g':
-            output_format = giellacg;
-            print_weights = true;
-            print_all = true;
-            dedupe = true;
-            if(max_weight_classes == std::numeric_limits<int>::max()) {
-                max_weight_classes = 2;
+            settings.output_format = giellacg;
+            settings.print_weights = true;
+            settings.print_all = true;
+            settings.dedupe = true;
+            settings.verbose = false;
+            if(settings.max_weight_classes == std::numeric_limits<int>::max()) {
+                settings.max_weight_classes = 2;
             }
             break;
         case 'f':
-            output_format = finnpos;
+            settings.output_format = finnpos;
             break;
 #include "inc/getopt-cases-error.h"
         }
@@ -1169,27 +505,42 @@ int main(int argc, char ** argv)
         return EXIT_FAILURE;
     }
     try {
-        hfst::HfstInputStream is(tokenizer_filename);
-        HfstTransducer dictionary(is);
-        if (first_transducer_is_called_TOP(dictionary)) {
+        // To decide whether we're working with something produced by a
+        // pmatch ruleset, we want to know whether the first transducer
+        // is named TOP. To do this, rather than load the whole thing
+        // into a HfstTransducer, we read just the header variables
+        // with a function in the hfst_ol namespace. This is not really the
+        // place for such a function, so perhaps it should be reimplemented
+        // as a static member of HfstTransducer in the future, TODO.
+        std::map<std::string, std::string> first_header_attributes;
+        try {
+            first_header_attributes = hfst_ol::PmatchContainer::parse_hfst3_header(instream);
             instream.seekg(0);
             instream.clear();
-            hfst_ol::PmatchContainer container(instream);
+        } catch(TransducerHeaderException & e) {
+            std::cerr << tokenizer_filename <<
+                " doesn't look like a HFST archive. Exiting.\n"
+                "Exception thrown:\n" << e.what() << std::endl;
+            return 1;
+        }
+        if (first_header_attributes.count("name") == 0 ||
+            first_header_attributes["name"] != "TOP") {
+            hfst::HfstInputStream is(tokenizer_filename);
+            HfstTransducer * dictionary = new HfstTransducer(is);
+            instream.close();
+            hfst_ol::PmatchContainer container = make_naive_tokenizer(dictionary);
+            delete dictionary;
             container.set_verbose(verbose);
-            container.set_single_codepoint_tokenization(!tokenize_multichar);
+            container.set_single_codepoint_tokenization(!settings.tokenize_multichar);
             return process_input(container, std::cout);
         } else {
-            instream.close();
-            hfst_ol::PmatchContainer container = make_naive_tokenizer(dictionary);
+            hfst_ol::PmatchContainer container(instream);
             container.set_verbose(verbose);
-            container.set_single_codepoint_tokenization(!tokenize_multichar);
+            container.set_single_codepoint_tokenization(!settings.tokenize_multichar);
             return process_input(container, std::cout);
         }
     } catch(HfstException & e) {
-        std::cerr << "The archive in " << tokenizer_filename <<
-            " doesn't look right.\nDid you make it with hfst-pmatch2fst"
-            " or make sure it's in weighted optimized-lookup format?\n"
-            "Exception thrown:\n" << e.what() << std::endl;
+        std::cerr << "Exception thrown:\n" << e.what() << std::endl;
         return 1;
     }
 
diff --git a/tools/src/hfst-twolc/src/hfst-twolc.cc b/tools/src/hfst-twolc/src/hfst-twolc.cc
index 630ae62..9bae207 100644
--- a/tools/src/hfst-twolc/src/hfst-twolc.cc
+++ b/tools/src/hfst-twolc/src/hfst-twolc.cc
@@ -161,6 +161,8 @@ int main(int argc, char * argv[])
       HfstOutputStream out
         (command_line.output_file_name,command_line.format);
       hfst::twolcpre3::get_grammar()->compile_and_store(out);
+      out.flush();
+      out.close();
     }
       exit(0);
     }
diff --git a/tools/src/hfst-twolc/test/test5 b/tools/src/hfst-twolc/test/test5
index e22c41b..8d04fc1 100644
--- a/tools/src/hfst-twolc/test/test5
+++ b/tools/src/hfst-twolc/test/test5
@@ -1,4 +1,4 @@
 Alphabet a b ;
 Rules
 "rule name"
-a:b => x [a*/b] _ ;
+a:b => x a+/b c _ ;
diff --git a/tools/src/hfst-twolc/test/test5.txt_fst b/tools/src/hfst-twolc/test/test5.txt_fst
index cd61f84..1ff14be 100644
--- a/tools/src/hfst-twolc/test/test5.txt_fst
+++ b/tools/src/hfst-twolc/test/test5.txt_fst
@@ -1,13 +1,29 @@
-0	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
 0	0	a	a	0.000000
 0	0	b	b	0.000000
-0	0	@#@	@_EPSILON_SYMBOL_@	0.000000
 0	1	x	x	0.000000
+0	0	c	c	0.000000
+0	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
+0	0	@#@	@0@	0.000000
 0	0.000000
-1	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
-1	0	a	b	0.000000
-1	0	@#@	@_EPSILON_SYMBOL_@	0.000000
-1	1	x	x	0.000000
-1	1	a	a	0.000000
+1	2	a	a	0.000000
 1	1	b	b	0.000000
+1	1	x	x	0.000000
+1	0	c	c	0.000000
+1	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
+1	0	@#@	@0@	0.000000
 1	0.000000
+2	2	a	a	0.000000
+2	2	b	b	0.000000
+2	1	x	x	0.000000
+2	3	c	c	0.000000
+2	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
+2	0	@#@	@0@	0.000000
+2	0.000000
+3	0	a	a	0.000000
+3	0	b	b	0.000000
+3	1	x	x	0.000000
+3	0	c	c	0.000000
+3	0	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@	0.000000
+3	0	@#@	@0@	0.000000
+3	0	a	b	0.000000
+3	0.000000
diff --git a/tools/src/parsers/hfst-xfst.cc b/tools/src/parsers/hfst-xfst.cc
index ddb127a..802b4c7 100644
--- a/tools/src/parsers/hfst-xfst.cc
+++ b/tools/src/parsers/hfst-xfst.cc
@@ -50,6 +50,7 @@ static char* startupfilename = NULL;
 static std::vector<char*> execute_commands;
 static bool pipe_input = false;
 static bool pipe_output = false; // this has no effect on non-windows platforms
+static bool restricted_mode = false;
 
 #ifdef HAVE_READLINE
   static bool use_readline = true;
@@ -78,6 +79,8 @@ print_usage()
           "  -p, --pipe-mode[=STREAM] Control input and output streams\n"
           "  -r, --no-readline        Do not use readline library for input\n"
           "  -w, --print-weight       Print weights for each operation\n"
+	  "  -R, --restricted-mode    Allow read and write operations only in current\n"
+	  "                           directory, do not allow system calls\n"
           //          "  -k, --no-console         Do not output directly to console (Windows-specific)\n"
           "\n"
           "Option --execute can be invoked many times.\n"
@@ -121,12 +124,13 @@ parse_options(int argc, char** argv)
             {"pipe-mode", optional_argument, 0, 'p'},
             {"no-readline", no_argument, 0, 'r'},
             {"print-weight", no_argument, 0, 'w'},
+	    {"restricted-mode", no_argument, 0, 'R'},
             //            {"no-console", no_argument, 0, 'k'},
             {0,0,0,0}
           };
         int option_index = 0;
         // add tool-specific options here
-        int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT "f:F:e:l:p::rwk",
+        int c = getopt_long(argc, argv, HFST_GETOPT_COMMON_SHORT "f:F:e:l:p::rwkR",
                              long_options, &option_index);
         if (-1 == c)
           {
@@ -196,7 +200,10 @@ parse_options(int argc, char** argv)
           case 'w':
             print_weight = true;
             break;
-          case 'k':
+	  case 'R':
+            restricted_mode = true;
+            break;
+	  case 'k':
             pipe_output = true;
             break;
 #include "inc/getopt-cases-error.h"
@@ -383,6 +390,11 @@ int main(int argc, char** argv)
       comp.setPromptVerbosity(true);
     }
 
+  if (restricted_mode)
+    {
+      comp.setRestrictedMode(true);
+    }
+  
   if (!pipe_output)
     comp.setOutputToConsole(true);
 
diff --git a/tools/src/parsers/test/Makefile.am b/tools/src/parsers/test/Makefile.am
index 31d3a86..3fd2b81 100644
--- a/tools/src/parsers/test/Makefile.am
+++ b/tools/src/parsers/test/Makefile.am
@@ -12,7 +12,9 @@ EXTRA_DIST=test.sh \
 	invert_net.xfst invert_net.att \
 	minus_net.xfst minus_net.att \
 	intersect_net.xfst intersect_net.att \
-	negate_net.xfst negate_net.att \
+	negate_net_1.xfst negate_net_1.att \
+	negate_net_2.xfst negate_net_2.att \
+	negate_net_fail.xfst \
 	one_plus_net.xfst one_plus_net.att \
 	zero_plus_net.xfst zero_plus_net.att \
 	determinize_net.xfst determinize_net.att \
@@ -51,7 +53,6 @@ EXTRA_DIST=test.sh \
 	quoted_literals.xfst quoted_literals.att \
 	define.xfst define.att \
 	define_function.xfst define_function.att \
-	define_fail.xfst \
 	eliminate_flag.xfst eliminate_flag.output \
 	empty_context.xfst empty_context.output \
 	set_variable.xfst set_variable.output \
diff --git a/tools/src/parsers/test/define_fail.xfst b/tools/src/parsers/test/define_fail.xfst
deleted file mode 100644
index f2ccbca..0000000
--- a/tools/src/parsers/test/define_fail.xfst
+++ /dev/null
@@ -1,3 +0,0 @@
-define Foo foo;
-regex Foo:bar;
-write att
diff --git a/tools/src/parsers/test/negate_net.att b/tools/src/parsers/test/negate_net.att
deleted file mode 100644
index b111a7a..0000000
--- a/tools/src/parsers/test/negate_net.att
+++ /dev/null
@@ -1,33 +0,0 @@
-0 1 @_UNKNOWN_SYMBOL_@ @_UNKNOWN_SYMBOL_@
-0 1 @_IDENTITY_SYMBOL_@ @_IDENTITY_SYMBOL_@
-0 1 @_UNKNOWN_SYMBOL_@ a
-0 1 @_UNKNOWN_SYMBOL_@ b
-0 1 a @_UNKNOWN_SYMBOL_@
-0 1 b @_UNKNOWN_SYMBOL_@
-0 1 a a
-0 1 b b
-0 1 b a
-0
-0 2 a b
-1 1 @_UNKNOWN_SYMBOL_@ @_UNKNOWN_SYMBOL_@
-1 1 @_IDENTITY_SYMBOL_@ @_IDENTITY_SYMBOL_@
-1 1 @_UNKNOWN_SYMBOL_@ a
-1 1 @_UNKNOWN_SYMBOL_@ b
-1 1 a @_UNKNOWN_SYMBOL_@
-1 1 b @_UNKNOWN_SYMBOL_@
-1 1 a b
-1 1 a a
-1 1 b b
-1 1 b a
-1
-2 1 @_UNKNOWN_SYMBOL_@ @_UNKNOWN_SYMBOL_@
-2 1 @_IDENTITY_SYMBOL_@ @_IDENTITY_SYMBOL_@
-2 1 @_UNKNOWN_SYMBOL_@ a
-2 1 @_UNKNOWN_SYMBOL_@ b
-2 1 a @_UNKNOWN_SYMBOL_@
-2 1 b @_UNKNOWN_SYMBOL_@
-2 1 a b
-2 1 a a
-2 1 b b
-2 1 b a
-
diff --git a/tools/src/parsers/test/negate_net_1.att b/tools/src/parsers/test/negate_net_1.att
new file mode 100644
index 0000000..a62bae1
--- /dev/null
+++ b/tools/src/parsers/test/negate_net_1.att
@@ -0,0 +1,11 @@
+0	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+0	1	a	a
+1	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+1	2	a	a
+2	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+2	2	a	a
+0
+2
+--
+0	1	a	a
+1
diff --git a/tools/src/parsers/test/negate_net.xfst b/tools/src/parsers/test/negate_net_1.xfst
similarity index 60%
copy from tools/src/parsers/test/negate_net.xfst
copy to tools/src/parsers/test/negate_net_1.xfst
index f958934..e01e2af 100644
--- a/tools/src/parsers/test/negate_net.xfst
+++ b/tools/src/parsers/test/negate_net_1.xfst
@@ -1,7 +1,10 @@
 regex d:e;
 regex c:d;
 regex b:c;
-regex a:b;
+regex a;
+negate net
+write att
+echo --
 negate net
 write att
 quit
diff --git a/tools/src/parsers/test/negate_net_2.att b/tools/src/parsers/test/negate_net_2.att
new file mode 100644
index 0000000..5daa881
--- /dev/null
+++ b/tools/src/parsers/test/negate_net_2.att
@@ -0,0 +1,11 @@
+0	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+0	1	@U.FOO.ON@	@U.FOO.ON@
+1	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+1	2	@U.FOO.ON@	@U.FOO.ON@
+2	2	@_IDENTITY_SYMBOL_@	@_IDENTITY_SYMBOL_@
+2	2	@U.FOO.ON@	@U.FOO.ON@
+0
+2
+--
+0	1	@U.FOO.ON@	@U.FOO.ON@
+1
diff --git a/tools/src/parsers/test/negate_net.xfst b/tools/src/parsers/test/negate_net_2.xfst
similarity index 54%
copy from tools/src/parsers/test/negate_net.xfst
copy to tools/src/parsers/test/negate_net_2.xfst
index f958934..5d64734 100644
--- a/tools/src/parsers/test/negate_net.xfst
+++ b/tools/src/parsers/test/negate_net_2.xfst
@@ -1,7 +1,10 @@
 regex d:e;
 regex c:d;
 regex b:c;
-regex a:b;
+regex "@U.FOO.ON@";
+negate net
+write att
+echo --
 negate net
 write att
 quit
diff --git a/tools/src/parsers/test/negate_net.xfst b/tools/src/parsers/test/negate_net_fail.xfst
similarity index 100%
rename from tools/src/parsers/test/negate_net.xfst
rename to tools/src/parsers/test/negate_net_fail.xfst
diff --git a/tools/src/parsers/test/test.sh b/tools/src/parsers/test/test.sh
index 1ee3566..235b7d6 100755
--- a/tools/src/parsers/test/test.sh
+++ b/tools/src/parsers/test/test.sh
@@ -102,8 +102,8 @@ do
     ## Test that the result of testfile.xfst (written in att format to standard output)
     ## is the same as testfile.att using att-to-fst conversion.
     for testfile in compose_net concatenate_net union_net ignore_net invert_net minus_net intersect_net \
-    determinize_net epsilon_remove_net invert_net minimize_net negate_net \
-    one_plus_net reverse_net upper_side_net zero_plus_net lower_side_net \
+    determinize_net epsilon_remove_net invert_net minimize_net \
+    one_plus_net reverse_net upper_side_net zero_plus_net lower_side_net negate_net_1 negate_net_2 \
     define define_function prolog \
         substitute_symbol_1 substitute_symbol_2 substitute_symbol_3 \
         substitute_symbol_4 substitute_symbol_5 \
@@ -168,22 +168,22 @@ do
     fi
 
 
-    ## Test that testfile_fail fails.
-    #for testfile in define_fail
-    #do
-#    if ! (ls $testfile.xfst 2> /dev/null); then
-#        echo "skipping missing test for "$testfile"..."
-#        continue
-#    fi
-#    if ! (cat $testfile.xfst | ../hfst-xfst -s -f $format 2> tmp > /dev/null); then
-#        echo "ERROR: in compiling "$testfile".xfst"
-#        exit 1;
-#    fi
-#    if ! (grep "xre parsing failed" tmp > /dev/null); then
-#        echo "ERROR: in "$testfile".xfst"
-#        exit 1;
-#    fi
-#    done
+    ## Failing tests
+    for testfile in negate_fail
+    do
+    if ! (ls $testfile.xfst 2> /dev/null); then
+        echo "skipping missing test for "$testfile"..."
+        continue
+    fi
+    if (cat $testfile.xfst | ../hfst-xfst -s -f $format 2> tmp > /dev/null); then
+        echo "ERROR: "$testfile".xfst should have failed"
+        exit 1;
+    fi
+    if ! (grep "Negation is defined only for automata" tmp > /dev/null); then
+        echo "ERROR: in "$testfile".xfst"
+        exit 1;
+    fi
+    done
 
     ## Test that the result of testfile.xfst (written to standard output)
     ## is the same as testfile.output
diff --git a/tools/src/sfst-main.cc b/tools/src/sfst-main.cc
index cc611f5..70682d1 100644
--- a/tools/src/sfst-main.cc
+++ b/tools/src/sfst-main.cc
@@ -25,7 +25,7 @@ using std::cerr;
 using namespace hfst;
 
 int switch_=0;
-hfst::ImplementationType output_format = hfst::ImplementationType::ERROR_TYPE;
+hfst::ImplementationType output_format = ERROR_TYPE;
 
 int Compact=0;
 int LowMem=0;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/hfst.git



More information about the debian-science-commits mailing list